summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp55
-rw-r--r--ApiDocs.bp6
-rw-r--r--INPUT_OWNERS1
-rw-r--r--apct-tests/perftests/core/AndroidManifest.xml1
-rw-r--r--apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java3
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java331
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java128
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java69
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java115
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java193
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java139
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java532
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java149
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java359
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java63
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java146
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java82
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java74
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java92
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java210
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java84
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java107
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java69
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java221
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java45
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java43
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java65
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java95
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java73
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java114
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java193
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java51
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java73
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java171
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java49
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java51
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java51
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java51
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java51
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java50
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java50
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java50
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java50
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java54
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java54
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java63
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java63
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java67
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java67
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java62
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java74
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java74
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java61
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java54
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java54
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java53
-rw-r--r--apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java53
-rwxr-xr-xapct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py515
-rw-r--r--apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java133
-rw-r--r--apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java5
-rw-r--r--apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt3
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java26
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java4
-rw-r--r--api/api.go2
-rw-r--r--boot/hiddenapi/hiddenapi-unsupported.txt1
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java3
-rw-r--r--cmds/bootanimation/BootAnimation.cpp22
-rw-r--r--cmds/bootanimation/FORMAT.md1
-rw-r--r--cmds/idmap2/Android.bp4
-rw-r--r--cmds/idmap2/tests/ResultTests.cpp5
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java12
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.cpp12
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.h1
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Device.java11
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Event.java13
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Uinput.java2
-rw-r--r--core/api/current.txt167
-rw-r--r--core/api/module-lib-current.txt14
-rw-r--r--core/api/system-current.txt47
-rw-r--r--core/api/test-current.txt53
-rw-r--r--core/java/Android.bp8
-rw-r--r--core/java/android/accounts/Account.java7
-rw-r--r--core/java/android/animation/AnimationHandler.java133
-rw-r--r--core/java/android/animation/Animator.java43
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/app/ActivityManager.java1
-rw-r--r--core/java/android/app/ActivityOptions.java28
-rw-r--r--core/java/android/app/ActivityThread.java63
-rw-r--r--core/java/android/app/ActivityThreadInternal.java2
-rw-r--r--core/java/android/app/ApplicationPackageManager.java31
-rw-r--r--core/java/android/app/ConfigurationController.java6
-rw-r--r--core/java/android/app/ContextImpl.java3
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl3
-rw-r--r--core/java/android/app/IWallpaperManager.aidl2
-rw-r--r--core/java/android/app/KeyguardManager.java5
-rw-r--r--core/java/android/app/Presentation.java2
-rw-r--r--core/java/android/app/ResourcesManager.java4
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/TEST_MAPPING17
-rw-r--r--core/java/android/app/TaskInfo.java10
-rw-r--r--core/java/android/app/UiAutomationConnection.java3
-rw-r--r--core/java/android/app/WallpaperManager.java40
-rw-r--r--core/java/android/app/WindowConfiguration.java22
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java43
-rw-r--r--core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS1
-rw-r--r--core/java/android/app/admin/WorkDeviceExperience_OWNERS1
-rw-r--r--core/java/android/app/ambientcontext/AmbientContextManager.java2
-rw-r--r--core/java/android/app/backup/BackupManager.java5
-rw-r--r--core/java/android/app/slice/ISliceManager.aidl2
-rw-r--r--core/java/android/app/slice/SliceManager.java14
-rw-r--r--core/java/android/app/slice/SliceProvider.java4
-rw-r--r--core/java/android/app/time/ExternalTimeSuggestion.java64
-rw-r--r--core/java/android/app/time/ITimeDetectorListener.aidl (renamed from services/tests/servicestests/src/com/android/server/appwidget/DummyAppWidget.java)23
-rw-r--r--core/java/android/app/time/TimeCapabilities.java99
-rw-r--r--core/java/android/app/time/TimeCapabilitiesAndConfig.java43
-rw-r--r--core/java/android/app/time/TimeConfiguration.java100
-rw-r--r--core/java/android/app/timedetector/GnssTimeSuggestion.java73
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl4
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java71
-rw-r--r--core/java/android/app/timedetector/NetworkTimeSuggestion.java80
-rw-r--r--core/java/android/app/timedetector/TelephonyTimeSuggestion.java57
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java30
-rw-r--r--core/java/android/app/timedetector/TimeSuggestionHelper.java209
-rw-r--r--core/java/android/apphibernation/AppHibernationManager.java17
-rw-r--r--core/java/android/apphibernation/IAppHibernationService.aidl2
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java37
-rw-r--r--core/java/android/appwidget/AppWidgetProvider.java7
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java6
-rw-r--r--core/java/android/appwidget/OWNERS1
-rw-r--r--core/java/android/companion/AssociationRequest.java15
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java64
-rw-r--r--core/java/android/companion/CompanionDeviceService.java44
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl7
-rw-r--r--core/java/android/companion/ICompanionDeviceService.aidl2
-rw-r--r--core/java/android/companion/SystemDataTransferRequest.java157
-rw-r--r--core/java/android/companion/datatransfer/PermissionSyncRequest.aidl (renamed from core/java/android/companion/SystemDataTransferRequest.aidl)4
-rw-r--r--core/java/android/companion/datatransfer/PermissionSyncRequest.java64
-rw-r--r--core/java/android/companion/datatransfer/SystemDataTransferRequest.java106
-rw-r--r--core/java/android/content/OWNERS1
-rw-r--r--core/java/android/content/SharedPreferences.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java20
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl23
-rw-r--r--core/java/android/content/pm/PackageInfo.java8
-rw-r--r--core/java/android/content/pm/PackageInstaller.java40
-rw-r--r--core/java/android/content/pm/PackageManager.java35
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/android/content/pm/UserInfo.java19
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java30
-rw-r--r--core/java/android/hardware/IConsumerIrService.aidl5
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java36
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java34
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java22
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java15
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java24
-rw-r--r--core/java/android/hardware/camera2/impl/CaptureCallback.java7
-rw-r--r--core/java/android/hardware/camera2/impl/CaptureResultExtras.java23
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java25
-rw-r--r--core/java/android/hardware/display/AmbientDisplayConfiguration.java3
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java27
-rw-r--r--core/java/android/hardware/face/FaceManager.java28
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/InputDeviceIdentifier.java6
-rw-r--r--core/java/android/hardware/input/InputManager.java89
-rw-r--r--core/java/android/hardware/input/KeyboardLayout.java13
-rw-r--r--core/java/android/hardware/input/OWNERS4
-rw-r--r--core/java/android/hardware/radio/ProgramSelector.java13
-rw-r--r--core/java/android/hardware/radio/RadioManager.java2
-rw-r--r--core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java4
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java37
-rw-r--r--core/java/android/nfc/INfcTag.aidl1
-rw-r--r--core/java/android/nfc/Tag.java23
-rwxr-xr-xcore/java/android/os/Build.java5
-rw-r--r--core/java/android/os/GraphicsEnvironment.java199
-rw-r--r--core/java/android/os/IBinder.java6
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/ServiceManager.java2
-rw-r--r--core/java/android/os/Trace.java24
-rw-r--r--core/java/android/os/UserHandle.java7
-rw-r--r--core/java/android/os/UserManager.java108
-rw-r--r--core/java/android/os/VibrationEffect.java18
-rw-r--r--core/java/android/os/Vibrator.java8
-rw-r--r--core/java/android/os/storage/OWNERS1
-rw-r--r--core/java/android/os/vibrator/VibratorFrequencyProfile.java3
-rw-r--r--core/java/android/permission/OWNERS10
-rw-r--r--core/java/android/permission/Permissions.md49
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/java/android/provider/Settings.java202
-rw-r--r--core/java/android/provider/Telephony.java12
-rw-r--r--core/java/android/security/attestationverification/AttestationVerificationManager.java56
-rw-r--r--core/java/android/service/autofill/FillContext.java4
-rw-r--r--core/java/android/service/autofill/FillRequest.java2
-rw-r--r--core/java/android/service/dreams/DreamActivity.java15
-rw-r--r--core/java/android/service/games/IGameService.aidl5
-rw-r--r--core/java/android/service/games/IGameServiceController.aidl3
-rw-r--r--core/java/android/service/games/IGameSession.aidl5
-rw-r--r--core/java/android/service/games/IGameSessionController.aidl4
-rw-r--r--core/java/android/service/games/IGameSessionService.aidl1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java6
-rw-r--r--core/java/android/service/oemlock/IOemLockService.aidl7
-rw-r--r--core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java4
-rw-r--r--core/java/android/service/voice/AbstractHotwordDetector.java37
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java475
-rw-r--r--core/java/android/service/voice/HotwordDetectionService.java32
-rw-r--r--core/java/android/service/voice/HotwordDetector.java86
-rw-r--r--core/java/android/service/voice/IHotwordDetectionService.aidl4
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java32
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java164
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java11
-rw-r--r--core/java/android/speech/OWNERS1
-rw-r--r--core/java/android/speech/SpeechRecognizer.java10
-rw-r--r--core/java/android/text/StaticLayout.java69
-rw-r--r--core/java/android/text/TextUtils.java5
-rw-r--r--core/java/android/text/format/Formatter.java239
-rw-r--r--core/java/android/util/FeatureFlagUtils.java11
-rw-r--r--core/java/android/view/Display.java18
-rw-r--r--core/java/android/view/DisplayInfo.java12
-rw-r--r--core/java/android/view/HandwritingInitiator.java173
-rw-r--r--core/java/android/view/IDisplayChangeWindowCallback.aidl (renamed from core/java/android/view/IDisplayWindowRotationCallback.aidl)10
-rw-r--r--core/java/android/view/IDisplayChangeWindowController.aidl (renamed from core/java/android/view/IDisplayWindowRotationController.aidl)24
-rw-r--r--core/java/android/view/IWindowManager.aidl36
-rw-r--r--core/java/android/view/InputDevice.java2
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java6
-rw-r--r--core/java/android/view/VelocityTracker.java4
-rw-r--r--core/java/android/view/View.java124
-rw-r--r--core/java/android/view/ViewConfiguration.java15
-rw-r--r--core/java/android/view/ViewRootImpl.java44
-rw-r--r--core/java/android/view/WindowManager.java64
-rw-r--r--core/java/android/view/WindowManagerGlobal.java2
-rw-r--r--core/java/android/view/WindowManagerPolicyConstants.java4
-rw-r--r--core/java/android/view/WindowlessWindowLayout.java39
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java4
-rw-r--r--core/java/android/view/autofill/AutofillManager.java92
-rw-r--r--core/java/android/view/autofill/AutofillRequestCallback.java72
-rw-r--r--core/java/android/view/autofill/IAutoFillManagerClient.aidl8
-rw-r--r--core/java/android/view/inputmethod/EditorBoundsInfo.java2
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java9
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionsRequest.java118
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java26
-rw-r--r--core/java/android/widget/AbsListView.java27
-rw-r--r--core/java/android/widget/EditText.java7
-rw-r--r--core/java/android/widget/Editor.java16
-rw-r--r--core/java/android/widget/HorizontalScrollView.java24
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java20
-rw-r--r--core/java/android/widget/ScrollView.java23
-rw-r--r--core/java/android/widget/TextView.java62
-rw-r--r--core/java/android/window/TaskFragmentInfo.java48
-rw-r--r--core/java/android/window/TransitionInfo.java9
-rw-r--r--core/java/android/window/TransitionRequestInfo.java4
-rw-r--r--core/java/android/window/WindowContainerTransaction.java31
-rw-r--r--core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java30
-rw-r--r--core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java23
-rw-r--r--core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java197
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java13
-rw-r--r--core/java/com/android/internal/appwidget/IAppWidgetService.aidl1
-rw-r--r--core/java/com/android/internal/appwidget/OWNERS2
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl22
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java5
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java10
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java2
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfigParser.java78
-rw-r--r--core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl2
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java18
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java5
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java57
-rw-r--r--core/java/com/android/internal/policy/BackdropFrameRenderer.java4
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java6
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java33
-rw-r--r--core/java/com/android/internal/usb/OWNERS1
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java10
-rw-r--r--core/java/com/android/internal/util/VirtualRefBasePtr.java13
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java17
-rw-r--r--core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java3
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java2
-rw-r--r--core/java/com/android/internal/widget/OWNERS2
-rw-r--r--core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java6
-rw-r--r--core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java10
-rw-r--r--core/jni/AndroidRuntime.cpp93
-rw-r--r--core/jni/OWNERS1
-rw-r--r--core/jni/android_media_AudioRecord.cpp8
-rw-r--r--core/jni/android_media_AudioTrack.cpp27
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp19
-rw-r--r--core/jni/android_os_Trace.cpp18
-rw-r--r--core/jni/android_util_Binder.h12
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp5
-rw-r--r--core/jni/android_view_SurfaceControl.cpp8
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp108
-rw-r--r--core/proto/OWNERS1
-rw-r--r--core/proto/android/os/system_properties.proto4
-rw-r--r--core/proto/android/providers/settings/global.proto4
-rw-r--r--core/proto/android/server/activitymanagerservice.proto1
-rw-r--r--core/proto/android/server/windowmanagertransitiontrace.proto68
-rw-r--r--core/res/AndroidManifest.xml18
-rw-r--r--core/res/res/drawable/ic_test_badge_experiment.xml24
-rw-r--r--core/res/res/drawable/ic_test_badge_no_background.xml24
-rw-r--r--core/res/res/drawable/ic_test_icon_badge_experiment.xml24
-rw-r--r--core/res/res/values-af/strings.xml33
-rw-r--r--core/res/res/values-am/strings.xml33
-rw-r--r--core/res/res/values-ar/strings.xml33
-rw-r--r--core/res/res/values-as/strings.xml33
-rw-r--r--core/res/res/values-az/strings.xml33
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml33
-rw-r--r--core/res/res/values-be/strings.xml33
-rw-r--r--core/res/res/values-bg/strings.xml33
-rw-r--r--core/res/res/values-bn/strings.xml33
-rw-r--r--core/res/res/values-bs/strings.xml33
-rw-r--r--core/res/res/values-ca/strings.xml33
-rw-r--r--core/res/res/values-cs/strings.xml33
-rw-r--r--core/res/res/values-da/strings.xml33
-rw-r--r--core/res/res/values-de/strings.xml33
-rw-r--r--core/res/res/values-el/strings.xml33
-rw-r--r--core/res/res/values-en-rAU/strings.xml33
-rw-r--r--core/res/res/values-en-rCA/strings.xml33
-rw-r--r--core/res/res/values-en-rGB/strings.xml33
-rw-r--r--core/res/res/values-en-rIN/strings.xml33
-rw-r--r--core/res/res/values-en-rXC/strings.xml33
-rw-r--r--core/res/res/values-es-rUS/strings.xml33
-rw-r--r--core/res/res/values-es/strings.xml33
-rw-r--r--core/res/res/values-et/strings.xml33
-rw-r--r--core/res/res/values-eu/strings.xml33
-rw-r--r--core/res/res/values-fa/strings.xml33
-rw-r--r--core/res/res/values-fi/strings.xml33
-rw-r--r--core/res/res/values-fr-rCA/strings.xml33
-rw-r--r--core/res/res/values-fr/strings.xml33
-rw-r--r--core/res/res/values-gl/strings.xml33
-rw-r--r--core/res/res/values-gu/strings.xml33
-rw-r--r--core/res/res/values-hi/strings.xml33
-rw-r--r--core/res/res/values-hr/strings.xml33
-rw-r--r--core/res/res/values-hu/strings.xml33
-rw-r--r--core/res/res/values-hy/strings.xml33
-rw-r--r--core/res/res/values-in/strings.xml33
-rw-r--r--core/res/res/values-is/strings.xml33
-rw-r--r--core/res/res/values-it/strings.xml33
-rw-r--r--core/res/res/values-iw/strings.xml33
-rw-r--r--core/res/res/values-ja/strings.xml33
-rw-r--r--core/res/res/values-ka/strings.xml33
-rw-r--r--core/res/res/values-kk/strings.xml33
-rw-r--r--core/res/res/values-km/strings.xml33
-rw-r--r--core/res/res/values-kn/strings.xml33
-rw-r--r--core/res/res/values-ko/strings.xml33
-rw-r--r--core/res/res/values-ky/strings.xml33
-rw-r--r--core/res/res/values-lo/strings.xml33
-rw-r--r--core/res/res/values-lt/strings.xml33
-rw-r--r--core/res/res/values-lv/strings.xml33
-rw-r--r--core/res/res/values-mk/strings.xml33
-rw-r--r--core/res/res/values-ml/strings.xml33
-rw-r--r--core/res/res/values-mn/strings.xml33
-rw-r--r--core/res/res/values-mr/strings.xml33
-rw-r--r--core/res/res/values-ms/strings.xml33
-rw-r--r--core/res/res/values-my/strings.xml33
-rw-r--r--core/res/res/values-nb/strings.xml33
-rw-r--r--core/res/res/values-ne/strings.xml33
-rw-r--r--core/res/res/values-nl/strings.xml33
-rw-r--r--core/res/res/values-or/strings.xml33
-rw-r--r--core/res/res/values-pa/strings.xml33
-rw-r--r--core/res/res/values-pl/strings.xml33
-rw-r--r--core/res/res/values-pt-rBR/strings.xml33
-rw-r--r--core/res/res/values-pt-rPT/strings.xml33
-rw-r--r--core/res/res/values-pt/strings.xml33
-rw-r--r--core/res/res/values-ro/strings.xml33
-rw-r--r--core/res/res/values-ru/strings.xml33
-rw-r--r--core/res/res/values-si/strings.xml33
-rw-r--r--core/res/res/values-sk/strings.xml33
-rw-r--r--core/res/res/values-sl/strings.xml33
-rw-r--r--core/res/res/values-sq/strings.xml33
-rw-r--r--core/res/res/values-sr/strings.xml33
-rw-r--r--core/res/res/values-sv/strings.xml33
-rw-r--r--core/res/res/values-sw/strings.xml33
-rw-r--r--core/res/res/values-ta/strings.xml33
-rw-r--r--core/res/res/values-te/strings.xml33
-rw-r--r--core/res/res/values-th/strings.xml33
-rw-r--r--core/res/res/values-tl/strings.xml33
-rw-r--r--core/res/res/values-tr/strings.xml33
-rw-r--r--core/res/res/values-uk/strings.xml33
-rw-r--r--core/res/res/values-ur/strings.xml33
-rw-r--r--core/res/res/values-uz/strings.xml33
-rw-r--r--core/res/res/values-vi/strings.xml33
-rw-r--r--core/res/res/values-zh-rCN/strings.xml33
-rw-r--r--core/res/res/values-zh-rHK/strings.xml33
-rw-r--r--core/res/res/values-zh-rTW/strings.xml33
-rw-r--r--core/res/res/values-zu/strings.xml33
-rw-r--r--core/res/res/values/attrs.xml53
-rw-r--r--core/res/res/values/attrs_manifest.xml5
-rw-r--r--core/res/res/values/config.xml51
-rw-r--r--core/res/res/values/dimens.xml6
-rw-r--r--core/res/res/values/public-staging.xml4
-rw-r--r--core/res/res/values/strings.xml42
-rw-r--r--core/res/res/values/styles.xml11
-rw-r--r--core/res/res/values/symbols.xml20
-rw-r--r--core/res/res/xml-watch/default_zen_mode_config.xml24
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/PackageInstallerSessions/Android.bp1
-rw-r--r--core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt210
-rw-r--r--core/tests/bugreports/Android.bp1
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/AndroidManifest.xml4
-rw-r--r--core/tests/coretests/src/android/app/KeyguardManagerTest.java217
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java48
-rw-r--r--core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java63
-rw-r--r--core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java180
-rw-r--r--core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java34
-rw-r--r--core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java34
-rw-r--r--core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java34
-rw-r--r--core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java43
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java6
-rw-r--r--core/tests/coretests/src/android/text/StaticLayoutTest.java21
-rw-r--r--core/tests/coretests/src/android/text/TextShaperTest.java14
-rw-r--r--core/tests/coretests/src/android/text/format/FormatterTest.java53
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java77
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java93
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java10
-rw-r--r--core/tests/coretests/src/android/window/BackNavigationTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java146
-rw-r--r--data/etc/services.core.protolog.json96
-rw-r--r--data/keyboards/Generic.kl4
-rw-r--r--errorprone/Android.bp3
-rw-r--r--errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java158
-rw-r--r--errorprone/tests/java/com/google/errorprone/bugpatterns/android/HideInCommentsCheckerTest.java235
-rw-r--r--graphics/java/android/graphics/Point.java12
-rw-r--r--graphics/java/android/graphics/fonts/Font.java2
-rw-r--r--graphics/java/android/graphics/text/LineBreakConfig.java52
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredential.java7
-rw-r--r--identity/java/android/security/identity/CredstoreWritableIdentityCredential.java5
-rw-r--r--identity/java/android/security/identity/PersonalizationData.java5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java4
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java119
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java22
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java9
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java52
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java186
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java31
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java69
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java57
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java42
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java32
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/util/DataProducer.java23
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml5
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java108
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java7
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java)14
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java173
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java90
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java6
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java4
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java24
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background.xml3
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml3
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings.xml16
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings.xml20
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml16
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml16
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings.xml18
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings_tv.xml13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java357
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java213
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java93
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java285
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java304
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java175
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java75
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java432
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java57
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java57
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java78
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java172
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java418
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java1314
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java117
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java110
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java150
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java326
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java85
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java762
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java376
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java348
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java99
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java386
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java209
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java97
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java93
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java63
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java186
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java64
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreen.aidl103
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreenListener.aidl33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/MainStage.java104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineManager.java181
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineView.java82
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SideStage.java144
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreen.java99
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenController.java595
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java292
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitscreenEventLogger.java324
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java1333
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java298
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskUnfoldController.java224
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java253
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java194
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt96
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt115
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt104
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt128
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt121
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt178
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt109
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt117
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt76
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt116
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt104
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt126
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt110
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt115
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt124
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt129
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt196
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt153
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt169
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt155
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt47
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt160
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt149
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt122
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt228
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt113
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt136
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt133
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt148
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt123
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt59
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java123
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java104
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java77
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java42
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java36
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java88
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java142
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java181
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java96
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java4
-rw-r--r--libs/androidfw/Android.bp5
-rw-r--r--libs/androidfw/AssetManager2.cpp4
-rw-r--r--libs/androidfw/BigBuffer.cpp (renamed from tools/aapt2/util/BigBuffer.cpp)6
-rw-r--r--libs/androidfw/StringPool.cpp (renamed from tools/aapt2/StringPool.cpp)49
-rw-r--r--libs/androidfw/Util.cpp124
-rw-r--r--libs/androidfw/include/androidfw/BigBuffer.h (renamed from tools/aapt2/util/BigBuffer.h)37
-rw-r--r--libs/androidfw/include/androidfw/IDiagnostics.h130
-rw-r--r--libs/androidfw/include/androidfw/Source.h (renamed from tools/aapt2/Source.h)16
-rw-r--r--libs/androidfw/include/androidfw/StringPiece.h4
-rw-r--r--libs/androidfw/include/androidfw/StringPool.h (renamed from tools/aapt2/StringPool.h)21
-rw-r--r--libs/androidfw/include/androidfw/Util.h43
-rw-r--r--libs/androidfw/tests/BigBuffer_test.cpp (renamed from tools/aapt2/util/BigBuffer_test.cpp)11
-rw-r--r--libs/androidfw/tests/StringPool_test.cpp (renamed from tools/aapt2/StringPool_test.cpp)94
-rw-r--r--libs/hwui/DeviceInfo.h2
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp3
-rw-r--r--libs/hwui/HardwareBitmapUploader.h3
-rw-r--r--libs/hwui/Readback.cpp12
-rw-r--r--libs/hwui/Readback.h6
-rw-r--r--libs/hwui/RecordingCanvas.cpp4
-rw-r--r--libs/hwui/RecordingCanvas.h2
-rw-r--r--libs/hwui/RenderNode.h1
-rw-r--r--libs/hwui/SkiaCanvas.cpp6
-rw-r--r--libs/hwui/SkiaCanvas.h2
-rw-r--r--libs/hwui/VectorDrawable.cpp5
-rw-r--r--libs/hwui/VectorDrawable.h1
-rw-r--r--libs/hwui/apex/android_bitmap.cpp5
-rw-r--r--libs/hwui/apex/android_canvas.cpp2
-rw-r--r--libs/hwui/canvas/CanvasOps.h12
-rw-r--r--libs/hwui/hwui/Bitmap.cpp8
-rw-r--r--libs/hwui/hwui/Bitmap.h2
-rw-r--r--libs/hwui/hwui/BlurDrawLooper.cpp1
-rw-r--r--libs/hwui/hwui/Canvas.cpp1
-rw-r--r--libs/hwui/hwui/Canvas.h1
-rw-r--r--libs/hwui/hwui/ImageDecoder.h2
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp5
-rw-r--r--libs/hwui/jni/AnimatedImageDrawable.cpp3
-rwxr-xr-xlibs/hwui/jni/Bitmap.cpp12
-rw-r--r--libs/hwui/jni/Bitmap.h1
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp10
-rw-r--r--libs/hwui/jni/BitmapRegionDecoder.cpp1
-rw-r--r--libs/hwui/jni/ByteBufferStreamAdaptor.cpp1
-rw-r--r--libs/hwui/jni/FontFamily.cpp1
-rw-r--r--libs/hwui/jni/GIFMovie.cpp2
-rw-r--r--libs/hwui/jni/Graphics.cpp8
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp6
-rw-r--r--libs/hwui/jni/Movie.h1
-rw-r--r--libs/hwui/jni/MovieImpl.cpp9
-rw-r--r--libs/hwui/jni/NinePatch.cpp2
-rw-r--r--libs/hwui/jni/NinePatchPeeker.cpp2
-rw-r--r--libs/hwui/jni/Paint.cpp1
-rw-r--r--libs/hwui/jni/Shader.cpp14
-rw-r--r--libs/hwui/jni/Utils.h3
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.cpp2
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.h4
-rw-r--r--libs/hwui/jni/android_graphics_Canvas.cpp14
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp10
-rw-r--r--libs/hwui/jni/fonts/Font.cpp3
-rw-r--r--libs/hwui/pipeline/skia/DumpOpsCanvas.h2
-rw-r--r--libs/hwui/pipeline/skia/HolePunch.h1
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp4
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp7
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp1
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp10
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp13
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h5
-rw-r--r--libs/hwui/pipeline/skia/TransformCanvas.cpp4
-rw-r--r--libs/hwui/pipeline/skia/TransformCanvas.h7
-rw-r--r--libs/hwui/renderthread/EglManager.h1
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h1
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderProxy.h6
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp2
-rw-r--r--libs/hwui/renderthread/VulkanManager.h3
-rw-r--r--libs/hwui/renderthread/VulkanSurface.h1
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp6
-rw-r--r--libs/hwui/tests/common/TestUtils.h10
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmap565.cpp6
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp1
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp11
-rw-r--r--libs/hwui/tests/common/scenes/MagnifierAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp6
-rw-r--r--libs/hwui/tests/common/scenes/RecentsAnimation.cpp5
-rw-r--r--libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp8
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp5
-rw-r--r--libs/hwui/tests/unit/CanvasOpTests.cpp10
-rw-r--r--libs/hwui/tests/unit/EglManagerTests.cpp2
-rw-r--r--libs/hwui/tests/unit/FatalTestCanvas.h2
-rw-r--r--libs/hwui/tests/unit/ShaderCacheTests.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp7
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp1
-rw-r--r--libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp1
-rw-r--r--libs/hwui/tests/unit/TypefaceTests.cpp3
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp6
-rw-r--r--libs/input/MouseCursorController.cpp6
-rw-r--r--libs/input/SpriteController.cpp3
-rw-r--r--libs/input/TouchSpotController.cpp6
-rw-r--r--location/java/android/location/Criteria.java13
-rw-r--r--location/java/android/location/Location.java103
-rw-r--r--location/java/android/location/LocationManager.java9
-rw-r--r--media/TEST_MAPPING3
-rw-r--r--media/aidl/android/media/audio/common/AudioPort.aidl5
-rw-r--r--media/aidl/android/media/audio/common/AudioPortExt.aidl5
-rw-r--r--media/aidl/android/media/audio/common/AudioPortMixExt.aidl4
-rw-r--r--media/java/android/media/AudioManager.java48
-rw-r--r--media/java/android/media/MediaCodec.java2
-rw-r--r--media/java/android/media/MediaFormat.java5
-rw-r--r--media/java/android/media/MediaMuxer.java4
-rw-r--r--media/java/android/media/MediaPlayer.java3
-rw-r--r--media/java/android/media/MediaRecorder.java8
-rw-r--r--media/java/android/media/audiofx/Visualizer.java27
-rw-r--r--media/java/android/media/tv/TvInputManager.java3
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java4
-rw-r--r--media/jni/Android.bp1
-rw-r--r--media/jni/audioeffect/Visualizer.cpp11
-rw-r--r--media/jni/audioeffect/Visualizer.h1
-rw-r--r--media/jni/audioeffect/android_media_SourceDefaultEffect.cpp4
-rw-r--r--media/jni/audioeffect/android_media_StreamDefaultEffect.cpp6
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp14
-rw-r--r--media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java36
-rw-r--r--native/android/surface_control.cpp15
-rw-r--r--native/graphics/jni/imagedecoder.cpp6
-rw-r--r--packages/CompanionDeviceManager/AndroidManifest.xml8
-rw-r--r--packages/CompanionDeviceManager/res/values-af/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-am/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ar/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-as/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-az/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-be/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-bg/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-bn/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-bs/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-ca/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-cs/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-da/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-de/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-el/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rAU/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rCA/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rGB/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rIN/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rXC/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-es-rUS/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-es/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-et/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-eu/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-fa/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-fi/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-fr/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-gl/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-gu/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-hi/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-hr/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-hu/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-hy/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-in/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-is/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-it/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-iw/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ja/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ka/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-kk/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-km/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-kn/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ko/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ky/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-lo/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-lt/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-lv/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-mk/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ml/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-mn/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-mr/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ms/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-my/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-nb/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ne/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-nl/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-or/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-pa/strings.xml31
-rw-r--r--packages/CompanionDeviceManager/res/values-pl/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-pt/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-ro/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ru/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-si/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-sk/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-sl/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-sq/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-sr/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-sv/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-sw/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-ta/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-te/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-th/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-tl/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-tr/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-uk/strings.xml29
-rw-r--r--packages/CompanionDeviceManager/res/values-ur/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-uz/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-vi/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values-zu/strings.xml27
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values/styles.xml1
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java1
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java48
-rw-r--r--packages/SettingsLib/ActionBarShadow/Android.bp5
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/AppPreference/Android.bp4
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml2
-rw-r--r--packages/SettingsLib/BarChartPreference/Android.bp4
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/Android.bp16
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/AndroidManifest.xml (renamed from packages/SystemUI/res/layout/auth_biometric_view.xml)13
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/AndroidSecureSettings.java (renamed from packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java)0
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java (renamed from packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java)0
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/SecureSettings.java (renamed from packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java)0
-rw-r--r--packages/SettingsLib/HelpUtils/Android.bp4
-rw-r--r--packages/SettingsLib/LayoutPreference/Android.bp6
-rw-r--r--packages/SettingsLib/ProgressBar/Android.bp4
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/Android.bp4
-rw-r--r--packages/SettingsLib/SearchWidget/Android.bp4
-rw-r--r--packages/SettingsLib/SettingsTheme/Android.bp6
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-mr/arrays.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml21
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml18
-rw-r--r--packages/SettingsLib/res/values/strings.xml40
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java48
-rw-r--r--packages/SettingsLib/tests/integ/Android.bp3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java12
-rw-r--r--packages/SettingsProvider/Android.bp2
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java14
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java18
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java10
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java10
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java26
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java59
-rw-r--r--packages/Shell/AndroidManifest.xml14
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java71
-rw-r--r--packages/SystemUI/Android.bp1
-rw-r--r--packages/SystemUI/OWNERS3
-rw-r--r--packages/SystemUI/compose/core/Android.bp38
-rw-r--r--packages/SystemUI/compose/core/AndroidManifest.xml (renamed from libs/WindowManager/Shell/res/color/unfold_transition_background.xml)13
-rw-r--r--packages/SystemUI/compose/core/TEST_MAPPING37
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt301
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt48
-rw-r--r--packages/SystemUI/compose/core/tests/Android.bp48
-rw-r--r--packages/SystemUI/compose/core/tests/AndroidManifest.xml28
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt43
-rw-r--r--packages/SystemUI/compose/features/Android.bp40
-rw-r--r--packages/SystemUI/compose/features/AndroidManifest.xml22
-rw-r--r--packages/SystemUI/compose/features/TEST_MAPPING26
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt55
-rw-r--r--packages/SystemUI/compose/features/tests/Android.bp48
-rw-r--r--packages/SystemUI/compose/features/tests/AndroidManifest.xml28
-rw-r--r--packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt53
-rw-r--r--packages/SystemUI/compose/gallery/Android.bp70
-rw-r--r--packages/SystemUI/compose/gallery/AndroidManifest.xml37
-rw-r--r--packages/SystemUI/compose/gallery/TEST_MAPPING15
-rw-r--r--packages/SystemUI/compose/gallery/proguard-rules.pro21
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml30
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml170
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webpbin0 -> 1404 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webpbin0 -> 2898 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webpbin0 -> 982 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webpbin0 -> 1772 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webpbin0 -> 1900 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webpbin0 -> 3918 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webpbin0 -> 2884 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webpbin0 -> 5914 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webpbin0 -> 3844 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webpbin0 -> 7778 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/values-night/themes.xml26
-rw-r--r--packages/SystemUI/compose/gallery/res/values/colors.xml19
-rw-r--r--packages/SystemUI/compose/gallery/res/values/strings.xml20
-rw-r--r--packages/SystemUI/compose/gallery/res/values/themes.xml27
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt89
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt86
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt29
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt56
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt127
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/HomeScreen.kt61
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt68
-rw-r--r--packages/SystemUI/compose/gallery/tests/Android.bp47
-rw-r--r--packages/SystemUI/compose/gallery/tests/AndroidManifest.xml28
-rw-r--r--packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt41
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java2
-rw-r--r--packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml725
-rw-r--r--packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml781
-rw-r--r--packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml144
-rw-r--r--packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml138
-rw-r--r--packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml268
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml6
-rw-r--r--packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_circular_unchecked.xml2
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_screen_saver.xml24
-rw-r--r--packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml22
-rw-r--r--packages/SystemUI/res/drawable/media_output_status_failed.xml2
-rw-r--r--packages/SystemUI/res/drawable/settings_input_antenna.xml23
-rw-r--r--packages/SystemUI/res/layout/broadcast_dialog.xml79
-rw-r--r--packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml28
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item.xml22
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml7
-rw-r--r--packages/SystemUI/res/layout/window_magnifier_view.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml26
-rw-r--r--packages/SystemUI/res/values-af/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-am/strings.xml26
-rw-r--r--packages/SystemUI/res/values-am/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ar/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-as/strings.xml26
-rw-r--r--packages/SystemUI/res/values-as/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-az/strings.xml26
-rw-r--r--packages/SystemUI/res/values-az/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml26
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-be/strings.xml26
-rw-r--r--packages/SystemUI/res/values-be/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml26
-rw-r--r--packages/SystemUI/res/values-bg/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml26
-rw-r--r--packages/SystemUI/res/values-bn/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml34
-rw-r--r--packages/SystemUI/res/values-bs/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ca/tiles_states_strings.xml7
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml26
-rw-r--r--packages/SystemUI/res/values-cs/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-da/strings.xml26
-rw-r--r--packages/SystemUI/res/values-da/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-de/strings.xml26
-rw-r--r--packages/SystemUI/res/values-de/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-el/strings.xml26
-rw-r--r--packages/SystemUI/res/values-el/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml26
-rw-r--r--packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml26
-rw-r--r--packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml26
-rw-r--r--packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml26
-rw-r--r--packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml26
-rw-r--r--packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml28
-rw-r--r--packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-es/strings.xml26
-rw-r--r--packages/SystemUI/res/values-es/tiles_states_strings.xml9
-rw-r--r--packages/SystemUI/res/values-et/strings.xml26
-rw-r--r--packages/SystemUI/res/values-et/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml26
-rw-r--r--packages/SystemUI/res/values-eu/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml26
-rw-r--r--packages/SystemUI/res/values-fa/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml26
-rw-r--r--packages/SystemUI/res/values-fi/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml26
-rw-r--r--packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml38
-rw-r--r--packages/SystemUI/res/values-fr/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-gl/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml26
-rw-r--r--packages/SystemUI/res/values-gu/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml26
-rw-r--r--packages/SystemUI/res/values-hi/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-hr/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml26
-rw-r--r--packages/SystemUI/res/values-hu/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml26
-rw-r--r--packages/SystemUI/res/values-hy/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-in/strings.xml26
-rw-r--r--packages/SystemUI/res/values-in/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-is/strings.xml26
-rw-r--r--packages/SystemUI/res/values-is/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-it/strings.xml26
-rw-r--r--packages/SystemUI/res/values-it/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml26
-rw-r--r--packages/SystemUI/res/values-iw/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ja/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ka/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml26
-rw-r--r--packages/SystemUI/res/values-kk/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-km/strings.xml26
-rw-r--r--packages/SystemUI/res/values-km/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml26
-rw-r--r--packages/SystemUI/res/values-kn/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ko/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ky/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml26
-rw-r--r--packages/SystemUI/res/values-lo/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml26
-rw-r--r--packages/SystemUI/res/values-lt/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml26
-rw-r--r--packages/SystemUI/res/values-lv/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml26
-rw-r--r--packages/SystemUI/res/values-mk/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ml/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml26
-rw-r--r--packages/SystemUI/res/values-mn/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml28
-rw-r--r--packages/SystemUI/res/values-mr/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ms/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-my/strings.xml26
-rw-r--r--packages/SystemUI/res/values-my/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml38
-rw-r--r--packages/SystemUI/res/values-nb/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ne/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-night/colors.xml10
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-nl/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-or/strings.xml26
-rw-r--r--packages/SystemUI/res/values-or/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pa/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml38
-rw-r--r--packages/SystemUI/res/values-pl/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pt/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ro/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml28
-rw-r--r--packages/SystemUI/res/values-ru/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-si/strings.xml26
-rw-r--r--packages/SystemUI/res/values-si/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sk/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sl/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sq/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sr/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sv/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sw/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-sw600dp-port/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/dimens.xml6
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml28
-rw-r--r--packages/SystemUI/res/values-ta/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-te/strings.xml26
-rw-r--r--packages/SystemUI/res/values-te/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-th/strings.xml26
-rw-r--r--packages/SystemUI/res/values-th/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-tl/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-tr/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml38
-rw-r--r--packages/SystemUI/res/values-uk/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ur/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml26
-rw-r--r--packages/SystemUI/res/values-uz/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml26
-rw-r--r--packages/SystemUI/res/values-vi/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zu/tiles_states_strings.xml5
-rw-r--r--packages/SystemUI/res/values/config.xml17
-rw-r--r--packages/SystemUI/res/values/dimens.xml62
-rw-r--r--packages/SystemUI/res/values/strings.xml46
-rw-r--r--packages/SystemUI/res/values/styles.xml46
-rw-r--r--packages/SystemUI/res/values/tiles_states_strings.xml10
-rw-r--r--packages/SystemUI/shared/Android.bp2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt65
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt146
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java78
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java42
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt49
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt35
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt51
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt61
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java59
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TextAnimator.kt106
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt89
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java269
-rw-r--r--packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt83
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java134
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt (renamed from packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt147
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt85
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt340
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt735
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt139
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java244
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionClassifier.kt)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionChangeEvent.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java147
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java224
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt123
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt269
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java324
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt171
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt85
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java241
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt209
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt166
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java)15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java5
-rw-r--r--packages/SystemUI/tools/lint/baseline.xml22
-rw-r--r--packages/SystemUI/unfold/Android.bp39
-rw-r--r--packages/SystemUI/unfold/AndroidManifest.xml22
-rw-r--r--packages/SystemUI/unfold/lint-baseline.xml3
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt)18
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt)4
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt)15
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt)4
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt56
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt54
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt41
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt)1
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt25
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt25
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt)0
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt)4
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt)91
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt26
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt)7
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt27
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt33
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt)14
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt)2
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt)14
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt20
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt22
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt)14
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt (renamed from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt)0
-rw-r--r--packages/VpnDialogs/res/values-gl/strings.xml2
-rw-r--r--packages/VpnDialogs/res/values-iw/strings.xml2
-rw-r--r--packages/VpnDialogs/res/values-km/strings.xml2
-rw-r--r--packages/VpnDialogs/res/values-or/strings.xml2
-rw-r--r--packages/VpnDialogs/res/values-sq/strings.xml2
-rw-r--r--proto/src/system_messages.proto8
-rw-r--r--services/Android.bp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java12
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java37
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java83
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java75
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java293
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java187
-rw-r--r--services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java68
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java23
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java67
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java5
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java18
-rw-r--r--services/companion/java/com/android/server/companion/CompanionApplicationController.java40
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java59
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java6
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java61
-rw-r--r--services/companion/java/com/android/server/companion/DataStoreUtils.java19
-rw-r--r--services/companion/java/com/android/server/companion/PackageUtils.java26
-rw-r--r--services/companion/java/com/android/server/companion/PermissionsUtils.java14
-rw-r--r--services/companion/java/com/android/server/companion/PersistentDataStore.java2
-rw-r--r--services/companion/java/com/android/server/companion/Utils.java47
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/CompanionMessageInfo.java50
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java229
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java269
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java (renamed from services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java)193
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java782
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java1574
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissions.java227
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/model/Permission.java414
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/ArrayUtils.java61
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/LocationUtils.java135
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/SoftRestrictedPermissionPolicy.java84
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/Utils.java819
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java6
-rw-r--r--services/companion/java/com/android/server/companion/proto/companion_apps_permissions.proto37
-rw-r--r--services/companion/java/com/android/server/companion/proto/companion_message.proto32
-rw-r--r--services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java121
-rw-r--r--services/companion/java/com/android/server/companion/securechannel/OWNERS4
-rw-r--r--services/companion/java/com/android/server/companion/virtual/InputController.java2
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java2
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/OWNERS1
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java40
-rw-r--r--services/core/java/com/android/server/BootReceiver.java43
-rw-r--r--services/core/java/com/android/server/ConsumerIrService.java17
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java4
-rw-r--r--services/core/java/com/android/server/LocalManagerRegistry.java26
-rw-r--r--services/core/java/com/android/server/MemoryPressureUtil.java56
-rw-r--r--services/core/java/com/android/server/ResourcePressureUtil.java78
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java7
-rw-r--r--services/core/java/com/android/server/SystemService.java28
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java33
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java23
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java5
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java60
-rw-r--r--services/core/java/com/android/server/Watchdog.java16
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java16
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java9
-rw-r--r--services/core/java/com/android/server/adb/AdbService.java34
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java172
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerUtils.java10
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java18
-rw-r--r--services/core/java/com/android/server/am/PendingStartActivityUids.java6
-rw-r--r--services/core/java/com/android/server/am/ProcessErrorStateRecord.java12
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java4
-rw-r--r--services/core/java/com/android/server/am/ReceiverList.java18
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java3
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java42
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java17
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java8
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java83
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java2
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java2
-rw-r--r--services/core/java/com/android/server/biometrics/OWNERS15
-rw-r--r--services/core/java/com/android/server/biometrics/Utils.java45
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java38
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RemovalClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java28
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java73
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java224
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java76
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java7
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java99
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java573
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java92
-rw-r--r--services/core/java/com/android/server/content/ContentService.java163
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java32
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java13
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java13
-rw-r--r--services/core/java/com/android/server/display/HighBrightnessModeController.java12
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java15
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java1
-rw-r--r--services/core/java/com/android/server/firewall/IntentFirewall.java14
-rw-r--r--services/core/java/com/android/server/firewall/SenderFilter.java27
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java25
-rw-r--r--services/core/java/com/android/server/input/GestureMonitorSpyWindow.java6
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java81
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java8
-rw-r--r--services/core/java/com/android/server/input/OWNERS4
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java28
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java8
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java5
-rw-r--r--services/core/java/com/android/server/logcat/LogcatManagerService.java1
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java10
-rw-r--r--services/core/java/com/android/server/media/TEST_MAPPING7
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryDatabase.java11
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java16
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java36
-rw-r--r--services/core/java/com/android/server/oemlock/OemLockService.java50
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java32
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java22
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java26
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java10
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerShellCommand.java148
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java556
-rw-r--r--services/core/java/com/android/server/pm/ApexPackageInfo.java397
-rw-r--r--services/core/java/com/android/server/pm/AppDataHelper.java35
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java98
-rw-r--r--services/core/java/com/android/server/pm/BroadcastParams.java62
-rw-r--r--services/core/java/com/android/server/pm/Computer.java65
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java418
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java14
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java14
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java16
-rw-r--r--services/core/java/com/android/server/pm/DistractingPackageHelper.java39
-rw-r--r--services/core/java/com/android/server/pm/DumpHelper.java12
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java47
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java68
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java111
-rw-r--r--services/core/java/com/android/server/pm/InstallParams.java16
-rw-r--r--services/core/java/com/android/server/pm/MovePackageHelper.java39
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java1
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java57
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerNative.java50
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java476
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java31
-rw-r--r--services/core/java/com/android/server/pm/PackageSessionVerifier.java128
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java5
-rw-r--r--services/core/java/com/android/server/pm/PreferredActivityHelper.java7
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/Settings.java7
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java11
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java57
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java20
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java333
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java5
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java6
-rw-r--r--services/core/java/com/android/server/pm/VerificationParams.java11
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java11
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java17
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java12
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java17
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java143
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java8
-rw-r--r--services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageState.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateImpl.java8
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java30
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java11
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java10
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java24
-rw-r--r--services/core/java/com/android/server/policy/GlobalKeyManager.java13
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java19
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java24
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java2
-rw-r--r--services/core/java/com/android/server/power/ShutdownCheckPoints.java9
-rw-r--r--services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java7
-rw-r--r--services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java252
-rw-r--r--services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java4
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java18
-rw-r--r--services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java7
-rw-r--r--services/core/java/com/android/server/testharness/OWNERS1
-rw-r--r--services/core/java/com/android/server/testharness/TestHarnessModeService.java6
-rw-r--r--services/core/java/com/android/server/timedetector/ConfigurationInternal.java278
-rw-r--r--services/core/java/com/android/server/timedetector/EnvironmentImpl.java90
-rw-r--r--services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java (renamed from services/core/java/com/android/server/NetworkTimeUpdateService.java)4
-rw-r--r--services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java (renamed from services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java)2
-rw-r--r--services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java216
-rw-r--r--services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java399
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java163
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java87
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java5
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java205
-rw-r--r--services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java7
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java7
-rw-r--r--services/core/java/com/android/server/tv/TvInputHal.java2
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java13
-rw-r--r--services/core/java/com/android/server/uri/UriPermissionOwner.java140
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java196
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecordInputSink.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java134
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java103
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java52
-rw-r--r--services/core/java/com/android/server/wm/AnrController.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java48
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java26
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java41
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java6
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java21
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java84
-rw-r--r--services/core/java/com/android/server/wm/DisplayHashController.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java39
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java107
-rw-r--r--services/core/java/com/android/server/wm/DragState.java16
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java5
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java2
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java11
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java29
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java46
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java17
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java572
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java118
-rw-r--r--services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java53
-rw-r--r--services/core/java/com/android/server/wm/RemoteDisplayChangeController.java171
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java61
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java17
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java4
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java251
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java77
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java100
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java5
-rw-r--r--services/core/java/com/android/server/wm/Transition.java274
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java79
-rw-r--r--services/core/java/com/android/server/wm/TransitionTracer.java234
-rw-r--r--services/core/java/com/android/server/wm/UnknownAppVisibilityController.java4
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowContainerThumbnail.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java141
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java739
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java235
-rw-r--r--services/core/java/com/android/server/wm/WindowOrientationListener.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java116
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java37
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java24
-rw-r--r--services/core/jni/Android.bp3
-rw-r--r--services/core/jni/OWNERS6
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp39
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java41
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java6
-rw-r--r--services/java/com/android/server/SystemServer.java99
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java4
-rw-r--r--services/selectiontoolbar/Android.bp22
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/Android.bp1
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml10
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml1
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java5
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java350
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp14
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml28
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp1
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java34
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt117
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt63
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt25
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt43
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java64
-rw-r--r--services/tests/servicestests/src/com/android/server/ambientcontext/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/TestAppWidgetProvider.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java150
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java140
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClientTest.java153
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java224
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java179
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java192
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java880
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java150
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java28
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java40
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java6
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java5
-rw-r--r--services/tests/wmtests/OWNERS3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java67
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java269
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java72
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java221
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java72
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java84
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java39
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java73
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java128
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java25
-rw-r--r--telecomm/java/android/telecom/Logging/EventManager.java6
-rw-r--r--telecomm/java/android/telecom/ParcelableCallAnalytics.java2
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java24
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl24
-rw-r--r--telephony/common/com/android/internal/telephony/util/TelephonyUtils.java1
-rw-r--r--telephony/java/android/telephony/DataFailCause.java7
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java52
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java8
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java40
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java2
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java8
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java4
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java136
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java3
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java62
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java12
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java80
-rw-r--r--test-base/api/TEST_MAPPING2
-rw-r--r--tests/ApkVerityTest/AndroidTest.xml2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt26
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml1
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java108
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java2
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java69
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java20
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java23
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java10
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java100
-rw-r--r--tools/aapt2/Android.bp6
-rw-r--r--tools/aapt2/ApkInfo.proto338
-rw-r--r--tools/aapt2/Debug.cpp111
-rw-r--r--tools/aapt2/Debug.h3
-rw-r--r--tools/aapt2/Diagnostics.h100
-rw-r--r--tools/aapt2/LoadedApk.cpp62
-rw-r--r--tools/aapt2/LoadedApk.h17
-rw-r--r--tools/aapt2/Main.cpp18
-rw-r--r--tools/aapt2/Resource.cpp6
-rw-r--r--tools/aapt2/Resource.h4
-rw-r--r--tools/aapt2/ResourceParser.cpp311
-rw-r--r--tools/aapt2/ResourceParser.h23
-rw-r--r--tools/aapt2/ResourceParser_test.cpp6
-rw-r--r--tools/aapt2/ResourceTable.cpp67
-rw-r--r--tools/aapt2/ResourceTable.h53
-rw-r--r--tools/aapt2/ResourceTable_test.cpp15
-rw-r--r--tools/aapt2/ResourceUtils.cpp92
-rw-r--r--tools/aapt2/ResourceUtils.h13
-rw-r--r--tools/aapt2/ResourceUtils_test.cpp2
-rw-r--r--tools/aapt2/ResourceValues.cpp37
-rw-r--r--tools/aapt2/ResourceValues.h41
-rw-r--r--tools/aapt2/ResourceValues_test.cpp22
-rw-r--r--tools/aapt2/Resource_test.cpp10
-rw-r--r--tools/aapt2/Resources.proto2
-rw-r--r--tools/aapt2/SdkConstants.cpp2
-rw-r--r--tools/aapt2/ValueTransformer.h8
-rw-r--r--tools/aapt2/ValueTransformer_inline.h4
-rw-r--r--tools/aapt2/cmd/ApkInfo.cpp94
-rw-r--r--tools/aapt2/cmd/ApkInfo.h49
-rw-r--r--tools/aapt2/cmd/ApkInfo_test.cpp78
-rw-r--r--tools/aapt2/cmd/Compile.cpp138
-rw-r--r--tools/aapt2/cmd/Compile.h16
-rw-r--r--tools/aapt2/cmd/Compile_test.cpp4
-rw-r--r--tools/aapt2/cmd/Convert.cpp78
-rw-r--r--tools/aapt2/cmd/Convert_test.cpp3
-rw-r--r--tools/aapt2/cmd/Diff.cpp34
-rw-r--r--tools/aapt2/cmd/Dump.cpp52
-rw-r--r--tools/aapt2/cmd/Dump.h58
-rw-r--r--tools/aapt2/cmd/Dump_test.cpp95
-rw-r--r--tools/aapt2/cmd/Link.cpp427
-rw-r--r--tools/aapt2/cmd/Link.h9
-rw-r--r--tools/aapt2/cmd/Link_test.cpp62
-rw-r--r--tools/aapt2/cmd/Optimize.cpp63
-rw-r--r--tools/aapt2/cmd/Optimize_test.cpp2
-rw-r--r--tools/aapt2/cmd/Util.cpp50
-rw-r--r--tools/aapt2/cmd/Util.h15
-rw-r--r--tools/aapt2/cmd/Util_test.cpp4
-rw-r--r--tools/aapt2/compile/IdAssigner.cpp37
-rw-r--r--tools/aapt2/compile/IdAssigner_test.cpp4
-rw-r--r--tools/aapt2/compile/InlineXmlFormatParser.cpp18
-rw-r--r--tools/aapt2/compile/Png.cpp84
-rw-r--r--tools/aapt2/compile/Png.h17
-rw-r--r--tools/aapt2/compile/PngCrunch.cpp36
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.cpp30
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.h7
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator_test.cpp40
-rw-r--r--tools/aapt2/compile/Pseudolocalizer.h5
-rw-r--r--tools/aapt2/compile/XmlIdCollector.cpp13
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.cpp150
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.h12
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.internal.h32
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp961
-rw-r--r--tools/aapt2/dump/DumpManifest.h10
-rw-r--r--tools/aapt2/format/Archive.cpp12
-rw-r--r--tools/aapt2/format/Archive.h9
-rw-r--r--tools/aapt2/format/Container.h7
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp209
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.h21
-rw-r--r--tools/aapt2/format/binary/ChunkWriter.h19
-rw-r--r--tools/aapt2/format/binary/ResChunkPullParser.cpp18
-rw-r--r--tools/aapt2/format/binary/ResChunkPullParser.h9
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp176
-rw-r--r--tools/aapt2/format/binary/TableFlattener.h9
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp51
-rw-r--r--tools/aapt2/format/binary/XmlFlattener.cpp66
-rw-r--r--tools/aapt2/format/binary/XmlFlattener.h7
-rw-r--r--tools/aapt2/format/binary/XmlFlattener_test.cpp7
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.cpp54
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.h21
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.cpp36
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.h15
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize_test.cpp89
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components.apkbin0 -> 84534 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected.txt56
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt165
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_full_proto.txt2310
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt5
-rw-r--r--tools/aapt2/integration-tests/DumpTest/minimal.apkbin0 -> 214221 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/minimal_expected.txt92
-rw-r--r--tools/aapt2/io/BigBufferStream.h12
-rw-r--r--tools/aapt2/io/File.h7
-rw-r--r--tools/aapt2/io/FileSystem.cpp12
-rw-r--r--tools/aapt2/io/FileSystem.h6
-rw-r--r--tools/aapt2/io/Util.cpp22
-rw-r--r--tools/aapt2/io/ZipArchive.cpp19
-rw-r--r--tools/aapt2/io/ZipArchive.h6
-rw-r--r--tools/aapt2/java/JavaClassGenerator.cpp21
-rw-r--r--tools/aapt2/java/ManifestClassGenerator.cpp24
-rw-r--r--tools/aapt2/java/ManifestClassGenerator.h5
-rw-r--r--tools/aapt2/java/ProguardRules.cpp2
-rw-r--r--tools/aapt2/java/ProguardRules.h7
-rw-r--r--tools/aapt2/link/AutoVersioner.cpp2
-rw-r--r--tools/aapt2/link/Linkers.h7
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp91
-rw-r--r--tools/aapt2/link/ManifestFixer.h2
-rw-r--r--tools/aapt2/link/NoDefaultResourceRemover.cpp12
-rw-r--r--tools/aapt2/link/PrivateAttributeMover.cpp5
-rw-r--r--tools/aapt2/link/PrivateAttributeMover_test.cpp12
-rw-r--r--tools/aapt2/link/ProductFilter.cpp30
-rw-r--r--tools/aapt2/link/ProductFilter_test.cpp40
-rw-r--r--tools/aapt2/link/ReferenceLinker.cpp36
-rw-r--r--tools/aapt2/link/ReferenceLinker.h5
-rw-r--r--tools/aapt2/link/ResourceExcluder.cpp9
-rw-r--r--tools/aapt2/link/TableMerger.cpp80
-rw-r--r--tools/aapt2/link/TableMerger.h10
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp2
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.cpp10
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.h6
-rw-r--r--tools/aapt2/link/XmlReferenceLinker.cpp18
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.cpp61
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.h10
-rw-r--r--tools/aapt2/optimize/ResourceDeduper.cpp11
-rw-r--r--tools/aapt2/optimize/ResourceFilter.cpp2
-rw-r--r--tools/aapt2/process/IResourceTableConsumer.h6
-rw-r--r--tools/aapt2/process/SymbolTable_test.cpp2
-rw-r--r--tools/aapt2/split/TableSplitter.cpp16
-rw-r--r--tools/aapt2/test/Builders.cpp6
-rw-r--r--tools/aapt2/test/Builders.h4
-rw-r--r--tools/aapt2/test/Common.cpp6
-rw-r--r--tools/aapt2/test/Common.h6
-rw-r--r--tools/aapt2/test/Context.h6
-rw-r--r--tools/aapt2/test/Fixture.cpp16
-rw-r--r--tools/aapt2/test/Fixture.h8
-rw-r--r--tools/aapt2/util/Files.cpp10
-rw-r--r--tools/aapt2/util/Files.h12
-rw-r--r--tools/aapt2/util/Util.cpp131
-rw-r--r--tools/aapt2/util/Util.h47
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.cpp22
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.h11
-rw-r--r--tools/aapt2/xml/XmlDom.cpp30
-rw-r--r--tools/aapt2/xml/XmlDom.h10
-rw-r--r--tools/aapt2/xml/XmlDom_test.cpp6
-rw-r--r--tools/bit/adb.cpp4
-rw-r--r--tools/bit/main.cpp126
-rw-r--r--tools/codegen/src/com/android/codegen/Generators.kt14
-rwxr-xr-xtools/codegen/src/com/android/codegen/Main.kt3
-rw-r--r--tools/lint/README.md1
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt28
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt375
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/EnforcePermissionDetector.kt155
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt524
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt209
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt38
-rw-r--r--tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt107
-rw-r--r--tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt241
-rw-r--r--tools/lint/checks/src/test/java/com/google/android/lint/EnforcePermissionDetectorTest.kt63
-rw-r--r--tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt271
-rw-r--r--tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt428
-rw-r--r--tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java2
-rw-r--r--tools/preload-check/device/src/com/android/preload/check/Util.java4
-rw-r--r--tools/processors/intdef_mappings/Android.bp22
-rw-r--r--tools/processors/view_inspector/Android.bp18
-rw-r--r--tools/validatekeymaps/OWNERS3
2230 files changed, 71772 insertions, 31352 deletions
diff --git a/Android.bp b/Android.bp
index df6fdaa5fdf6..7db16f62b2c4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -265,6 +265,60 @@ java_defaults {
],
aidl: {
generate_get_transaction_name: true,
+ enforce_permissions: true,
+ enforce_permissions_exceptions: [
+ // Do not add entries to this list.
+ ":framework-annotations",
+ ":framework-blobstore-sources",
+ ":framework-core-sources",
+ ":framework-drm-sources",
+ ":framework-graphics-nonupdatable-sources",
+ ":framework-jobscheduler-sources",
+ ":framework-keystore-sources",
+ ":framework-identity-sources",
+ ":framework-location-sources",
+ ":framework-lowpan-sources",
+ ":framework-mca-effect-sources",
+ ":framework-mca-filterfw-sources",
+ ":framework-mca-filterpacks-sources",
+ ":framework-media-non-updatable-sources",
+ ":framework-mms-sources",
+ ":framework-omapi-sources",
+ ":framework-opengl-sources",
+ ":framework-rs-sources",
+ ":framework-sax-sources",
+ ":framework-telecomm-sources",
+ ":framework-telephony-common-sources",
+ ":framework-telephony-sources",
+ ":framework-vcn-util-sources",
+ ":framework-wifi-annotations",
+ ":framework-wifi-non-updatable-sources",
+ ":PacProcessor-aidl-sources",
+ ":ProxyHandler-aidl-sources",
+ ":net-utils-framework-common-srcs",
+ ":platform-compat-native-aidl",
+ ":credstore_aidl",
+ ":dumpstate_aidl",
+ ":framework_native_aidl",
+ ":gatekeeper_aidl",
+ ":gsiservice_aidl",
+ ":idmap2_aidl",
+ ":idmap2_core_aidl",
+ ":incidentcompanion_aidl",
+ ":inputconstants_aidl",
+ ":installd_aidl",
+ ":libaudioclient_aidl",
+ ":libbinder_aidl",
+ ":libbluetooth-binder-aidl",
+ ":libcamera_client_aidl",
+ ":libcamera_client_framework_aidl",
+ ":libupdate_engine_aidl",
+ ":logd_aidl",
+ ":resourcemanager_aidl",
+ ":storaged_aidl",
+ ":vold_aidl",
+ ":deviceproductinfoconstants_aidl",
+ ],
local_include_dirs: [
"media/aidl",
],
@@ -351,6 +405,7 @@ java_library {
],
lint: {
extra_check_modules: ["AndroidFrameworkLintChecker"],
+ disabled_checks: ["ApiMightLeakAppVisibility"],
},
errorprone: {
javacflags: [
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 5ec107da8b94..e6525c9b8eaa 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -139,11 +139,7 @@ droidstubs {
defaults: ["android-non-updatable-doc-stubs-defaults"],
srcs: [":all-modules-public-stubs-source"],
args: metalava_framework_docs_args,
- api_levels_annotations_enabled: true,
- api_levels_annotations_dirs: [
- "sdk-dir",
- "api-versions-jars-dir",
- ],
+ api_levels_module: "api_versions_public",
aidl: {
include_dirs: [
"packages/modules/Connectivity/framework/aidl-export",
diff --git a/INPUT_OWNERS b/INPUT_OWNERS
index 6041f637f9c1..051216fdf3c6 100644
--- a/INPUT_OWNERS
+++ b/INPUT_OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 136048
michaelwr@google.com
prabirmsp@google.com
svv@google.com
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index e0c11cf0e3d5..56fa70cfc220 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<application>
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 517e3ce39d7e..31c92ba5e207 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -70,6 +70,9 @@ public class ZipFilePerfTest {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ZipFile zf = new ZipFile(mFile);
+ state.pauseTiming();
+ zf.close();
+ state.resumeTiming();
}
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
new file mode 100644
index 000000000000..d38d5197b937
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class AnnotatedElementPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Class<?> mType;
+ private Field mField;
+ private Method mMethod;
+
+ @Before
+ public void setUp() throws Exception {
+ mType = Type.class;
+ mField = Type.class.getField("field");
+ mMethod = Type.class.getMethod("method", String.class);
+ }
+
+ // get annotations by member type and method
+
+ @Test
+ public void timeGetTypeAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetFieldAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetMethodAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetParameterAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getParameterAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetTypeAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeGetFieldAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeGetMethodAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsTypeAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsFieldAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsMethodAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ // get annotations by result size
+
+ @Test
+ public void timeGetAllReturnsLargeAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasLargeAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsSmallAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsMarkerAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasMarkerAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsNoAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasNoAnnotations.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsThreeAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasThreeAnnotations.class.getAnnotations();
+ }
+ }
+
+ // get annotations with inheritance
+
+ @Test
+ public void timeGetAnnotationsOnSubclass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ExtendsHasThreeAnnotations.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetDeclaredAnnotationsOnSubclass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ExtendsHasThreeAnnotations.class.getDeclaredAnnotations();
+ }
+ }
+
+ // get annotations with enclosing / inner classes
+
+ @Test
+ public void timeGetDeclaredClasses() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ AnnotatedElementPerfTest.class.getDeclaredClasses();
+ }
+ }
+
+ @Test
+ public void timeGetDeclaringClass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getDeclaringClass();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingClass() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingClass();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingConstructor() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingConstructor();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingMethod() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingMethod();
+ }
+ }
+
+ @Test
+ public void timeGetModifiers() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getModifiers();
+ }
+ }
+
+ @Test
+ public void timeGetSimpleName() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getSimpleName();
+ }
+ }
+
+ @Test
+ public void timeIsAnonymousClass() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().isAnonymousClass();
+ }
+ }
+
+ @Test
+ public void timeIsLocalClass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.isLocalClass();
+ }
+ }
+
+ // the annotated elements
+
+ @Marker
+ public class Type {
+ @Marker public String field;
+
+ @Marker
+ public void method(@Marker String parameter) {}
+ }
+
+ @Large(
+ a = "on class",
+ b = {"A", "B", "C"},
+ c = @Small(e = "E1", f = 1695938256, g = 7264081114510713000L),
+ d = {@Small(e = "E2", f = 1695938256, g = 7264081114510713000L)})
+ public class HasLargeAnnotation {}
+
+ @Small(e = "E1", f = 1695938256, g = 7264081114510713000L)
+ public class HasSmallAnnotation {}
+
+ @Marker
+ public class HasMarkerAnnotation {}
+
+ public class HasNoAnnotations {}
+
+ @Large(
+ a = "on class",
+ b = {"A", "B", "C"},
+ c = @Small(e = "E1", f = 1695938256, g = 7264081114510713000L),
+ d = {@Small(e = "E2", f = 1695938256, g = 7264081114510713000L)})
+ @Small(e = "E1", f = 1695938256, g = 7264081114510713000L)
+ @Marker
+ public class HasThreeAnnotations {}
+
+ public class ExtendsHasThreeAnnotations extends HasThreeAnnotations {}
+
+ // the annotations
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Marker {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Large {
+ String a() default "";
+
+ String[] b() default {};
+
+ Small c() default @Small;
+
+ Small[] d() default {};
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Small {
+ String e() default "";
+
+ int f() default 0;
+
+ long g() default 0L;
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
new file mode 100644
index 000000000000..cc56868468e5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigDecimal;
+import java.text.AttributedCharacterIterator;
+import java.text.Bidi;
+import java.text.DecimalFormat;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BidiPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final AttributedCharacterIterator CHAR_ITER =
+ DecimalFormat.getInstance().formatToCharacterIterator(new BigDecimal(Math.PI));
+
+ @Test
+ public void time_createBidiFromIter() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bidi = new Bidi(CHAR_ITER);
+ }
+ }
+
+ @Test
+ public void time_createBidiFromCharArray() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ new char[] {'s', 's', 's'},
+ 0,
+ new byte[] {(byte) 1, (byte) 2, (byte) 3},
+ 0,
+ 3,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ }
+ }
+
+ @Test
+ public void time_createBidiFromString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bidi = new Bidi("Hello", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ }
+ }
+
+ @Test
+ public void time_reorderVisually() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi.reorderVisually(
+ new byte[] {2, 1, 3, 0, 4}, 0, new String[] {"H", "e", "l", "l", "o"}, 0, 5);
+ }
+ }
+
+ @Test
+ public void time_hebrewBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ new char[] {'\u05D0', '\u05D0', '\u05D0'},
+ 0,
+ new byte[] {(byte) -1, (byte) -2, (byte) -3},
+ 0,
+ 3,
+ Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ bd =
+ new Bidi(
+ new char[] {'\u05D0', '\u05D0', '\u05D0'},
+ 0,
+ new byte[] {(byte) -1, (byte) -2, (byte) -3},
+ 0,
+ 3,
+ Bidi.DIRECTION_LEFT_TO_RIGHT);
+ }
+ }
+
+ @Test
+ public void time_complicatedOverrideBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ "a\u05D0a\"a\u05D0\"\u05D0a".toCharArray(),
+ 0,
+ new byte[] {0, 0, 0, -3, -3, 2, 2, 0, 3},
+ 0,
+ 9,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ }
+ }
+
+ @Test
+ public void time_requiresBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1); // false.
+ Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1); // true.
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
new file mode 100644
index 000000000000..662694b1b5d1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BigIntegerPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeRandomDivision() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.divide(y);
+ }
+ }
+
+ @Test
+ public void timeRandomGcd() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.gcd(y);
+ }
+ }
+
+ @Test
+ public void timeRandomMultiplication() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.multiply(y);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
new file mode 100644
index 000000000000..db5462cd69bf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class BitSetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mSize={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{1000}, {10000}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int mSize;
+
+ private BitSet mBitSet;
+
+ @Before
+ public void setUp() throws Exception {
+ mBitSet = new BitSet(mSize);
+ }
+
+ @Test
+ public void timeIsEmptyTrue() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ if (!mBitSet.isEmpty()) throw new RuntimeException();
+ }
+ }
+
+ @Test
+ public void timeIsEmptyFalse() {
+ mBitSet.set(mBitSet.size() - 1);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ if (mBitSet.isEmpty()) throw new RuntimeException();
+ }
+ }
+
+ @Test
+ public void timeGet() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 1;
+ while (state.keepRunning()) {
+ mBitSet.get(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeClear() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 1;
+ while (state.keepRunning()) {
+ mBitSet.clear(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeSet() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeSetOn() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize, true);
+ }
+ }
+
+ @Test
+ public void timeSetOff() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize, false);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
new file mode 100644
index 000000000000..3952c12b3bfe
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.text.BreakIterator;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public final class BreakIteratorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum Text {
+ LIPSUM(
+ Locale.US,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi mollis consequat"
+ + " nisl non pharetra. Praesent pretium vehicula odio sed ultrices. Aenean a"
+ + " felis libero. Vivamus sed commodo nibh. Pellentesque turpis lectus, euismod"
+ + " vel ante nec, cursus posuere orci. Suspendisse velit neque, fermentum"
+ + " luctus ultrices in, ultrices vitae arcu. Duis tincidunt cursus lorem. Nam"
+ + " ultricies accumsan quam vitae imperdiet. Pellentesque habitant morbi"
+ + " tristique senectus et netus et malesuada fames ac turpis egestas. Quisque"
+ + " aliquet pretium nisi, eget laoreet enim molestie sit amet. Class aptent"
+ + " taciti sociosqu ad litora torquent per conubia nostra, per inceptos"
+ + " himenaeos.\n"
+ + "Nam dapibus aliquam lacus ac suscipit. Proin in nibh sit amet purus congue"
+ + " laoreet eget quis nisl. Morbi gravida dignissim justo, a venenatis ante"
+ + " pulvinar at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin"
+ + " ultrices vestibulum dui, vel aliquam lacus aliquam quis. Duis fringilla"
+ + " sapien ac lacus egestas, vel adipiscing elit euismod. Donec non tellus"
+ + " odio. Donec gravida eu massa ac feugiat. Aliquam erat volutpat. Praesent id"
+ + " adipiscing metus, nec laoreet enim. Aliquam vitae posuere turpis. Mauris ac"
+ + " pharetra sem. In at placerat tortor. Vivamus ac vehicula neque. Cras"
+ + " volutpat ullamcorper massa et varius. Praesent sagittis neque vitae nulla"
+ + " euismod pharetra.\n"
+ + "Sed placerat sapien non molestie sollicitudin. Nullam sit amet dictum quam."
+ + " Etiam tincidunt tortor vel pretium vehicula. Praesent fringilla ipsum vel"
+ + " velit luctus dignissim. Nulla massa ligula, mattis in enim et, mattis"
+ + " lacinia odio. Suspendisse tristique urna a orci commodo tempor. Duis"
+ + " lacinia egestas arcu a sollicitudin.\n"
+ + "In ac feugiat lacus. Nunc fermentum eu est at tristique. Pellentesque quis"
+ + " ligula et orci placerat lacinia. Maecenas quis mauris diam. Etiam mi ipsum,"
+ + " tempus in purus quis, euismod faucibus orci. Nulla facilisi. Praesent sit"
+ + " amet sapien vel elit porta adipiscing. Phasellus sit amet volutpat diam.\n"
+ + "Proin bibendum elit non lacus pharetra, quis eleifend tellus placerat. Nulla"
+ + " facilisi. Maecenas ante diam, pellentesque mattis mattis in, porta ut"
+ + " lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices"
+ + " posuere cubilia Curae; Nunc interdum tristique metus, in scelerisque odio"
+ + " fermentum eget. Cras nec venenatis lacus. Aenean euismod eget metus quis"
+ + " molestie. Cras tincidunt dolor ut massa ornare, in elementum lacus auctor."
+ + " Cras sodales nisl lacus, id ultrices ligula varius at. Sed tristique sit"
+ + " amet tellus vel mollis. Sed sed sollicitudin quam. Sed sed adipiscing"
+ + " risus, et dictum orci. Cras tempor pellentesque turpis et tempus."),
+ LONGPARA(
+ Locale.US,
+ "During dinner, Mr. Bennet scarcely spoke at all; but when the servants were"
+ + " withdrawn, he thought it time to have some conversation with his guest, and"
+ + " therefore started a subject in which he expected him to shine, by observing"
+ + " that he seemed very fortunate in his patroness. Lady Catherine de Bourgh's"
+ + " attention to his wishes, and consideration for his comfort, appeared very"
+ + " remarkable. Mr. Bennet could not have chosen better. Mr. Collins was"
+ + " eloquent in her praise. The subject elevated him to more than usual"
+ + " solemnity of manner, and with a most important aspect he protested that"
+ + " \"he had never in his life witnessed such behaviour in a person of"
+ + " rank--such affability and condescension, as he had himself experienced from"
+ + " Lady Catherine. She had been graciously pleased to approve of both of the"
+ + " discourses which he had already had the honour of preaching before her. She"
+ + " had also asked him twice to dine at Rosings, and had sent for him only the"
+ + " Saturday before, to make up her pool of quadrille in the evening. Lady"
+ + " Catherine was reckoned proud by many people he knew, but _he_ had never"
+ + " seen anything but affability in her. She had always spoken to him as she"
+ + " would to any other gentleman; she made not the smallest objection to his"
+ + " joining in the society of the neighbourhood nor to his leaving the parish"
+ + " occasionally for a week or two, to visit his relations. She had even"
+ + " condescended to advise him to marry as soon as he could, provided he chose"
+ + " with discretion; and had once paid him a visit in his humble parsonage,"
+ + " where she had perfectly approved all the alterations he had been making,"
+ + " and had even vouchsafed to suggest some herself--some shelves in the closet"
+ + " up stairs.\""),
+ GERMAN(
+ Locale.GERMANY,
+ "Aber dieser Freiheit setzte endlich der Winter ein Ziel. Draußen auf den Feldern"
+ + " und den hohen Bergen lag der Schnee und Peter wäre in seinem dünnen"
+ + " Leinwandjäckchen bald erfroren. Es war also seine einzige Freude, hinaus"
+ + " vor die Hütte zu treten und den Sperlingen Brotkrümchen zu streuen, was er"
+ + " sich jedesmal an seinem Frühstück absparte. Wenn nun die Vögel so lustig"
+ + " zwitscherten und um ihn herumflogen, da klopfte ihm das Herz vor Lust, und"
+ + " oft gab er ihnen sein ganzes Stück Schwarzbrot, ohne daran zu denken, daß"
+ + " er dafür alsdann selbst hungern müsse."),
+ THAI(
+ Locale.forLanguageTag("th-TH"),
+ "เป็นสำเนียงทางการของภาษาไทย"
+ + " เดิมทีเป็นการผสมผสานกันระหว่างสำเนียงอยุธยาและชาวไทยเชื้อสายจีนรุ่นหลังที่"
+ + "พูดไทยแทนกลุ่มภาษาจีน"
+ + " ลักษณะเด่นคือมีการออกเสียงที่ชัดเจนและแข็งกระด้างซึ่งได้รับอิทธิพลจากภาษาแต"
+ + "้จิ๋ว"
+ + " การออกเสียงพยัญชนะ สระ การผันวรรณยุกต์ที่ในภาษาไทยมาตรฐาน"
+ + " มาจากสำเนียงถิ่นนี้ในขณะที่ภาษาไทยสำเนียงอื่นล้วนเหน่อทั้งสิ้น"
+ + " คำศัพท์ที่ใช้ในสำเนียงกรุงเทพจำนวนมากได้รับมาจากกลุ่มภาษาจีนเช่นคำว่า โป๊,"
+ + " เฮ็ง, อาหมวย, อาซิ่ม ซึ่งมาจากภาษาแต้จิ๋ว และจากภาษาจีนเช่น ถู(涂), ชิ่ว(去"
+ + " อ่านว่า\"ชู่\") และคำว่า ทาย(猜 อ่านว่า \"ชาย\") เป็นต้น"
+ + " เนื่องจากสำเนียงกรุงเทพได้รับอิทธิพลมาจากภาษาจีนดังนั้นตัวอักษร \"ร\""
+ + " มักออกเสียงเหมารวมเป็น \"ล\" หรือคำควบกล่ำบางคำถูกละทิ้งไปด้วยเช่น รู้ เป็น"
+ + " ลู้, เรื่อง เป็น เลื่อง หรือ ประเทศ เป็น ปะเทศ"
+ + " เป็นต้นสร้างความลำบากให้แก่ต่างชาติที่ต้องการเรียนภาษาไทย"
+ + " แต่อย่างไรก็ตามผู้ที่พูดสำเนียงถิ่นนี้ก็สามารถออกอักขระภาษาไทยตามมาตรฐานได"
+ + "้อย่างถูกต้องเพียงแต่มักเผลอไม่ค่อยออกเสียง"),
+ THAI2(Locale.forLanguageTag("th-TH"), "this is the word browser in Thai: เบราว์เซอร์"),
+ TABS(Locale.US, "one\t\t\t\t\t\t\t\t\t\t\t\t\t\ttwo\n"),
+ ACCENT(Locale.US, "e\u0301\u00e9\nwhich is:\n\"e\\u0301\\u00e9\""),
+ EMOJI(Locale.US, ">>\ud83d\ude01<<\nwhich is:\n\">>\\ud83d\\ude01<<\""),
+ SPACES(Locale.US, " leading spaces and trailing ones too "),
+ EMPTY(Locale.US, ""),
+ NEWLINE(Locale.US, "\\n:\n"),
+ BIDI(
+ Locale.forLanguageTag("he-IL"),
+ "Sarah שרה is spelled sin ש resh ר heh ה from right to left.");
+
+ final Locale mLocale;
+ final String mText;
+
+ Text(Locale locale, String text) {
+ this.mText = text;
+ this.mLocale = locale;
+ }
+ }
+
+ @Parameters(name = "mText={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {Text.ACCENT}, {Text.BIDI}, {Text.EMOJI}, {Text.EMPTY}, {Text.GERMAN},
+ {Text.LIPSUM}, {Text.LONGPARA}, {Text.NEWLINE}, {Text.SPACES}, {Text.TABS},
+ {Text.THAI}, {Text.THAI2}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public Text mText;
+
+ @Test
+ public void timeBreakIterator() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ BreakIterator it = BreakIterator.getLineInstance(mText.mLocale);
+ it.setText(mText.mText);
+
+ while (it.next() != BreakIterator.DONE) {
+ // Keep iterating
+ }
+ }
+ }
+
+ @Test
+ public void timeIcuBreakIterator() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ android.icu.text.BreakIterator it =
+ android.icu.text.BreakIterator.getLineInstance(mText.mLocale);
+ it.setText(mText.mText);
+
+ while (it.next() != android.icu.text.BreakIterator.DONE) {
+ // Keep iterating
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java
new file mode 100644
index 000000000000..8e57b28a0550
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferBulkPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mAligned({0}), mSrcBufferType({1}), mDataBufferType({2}), mBufferSize({3})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {true, MyBufferType.DIRECT, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.DIRECT, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.DIRECT, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.MAPPED, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.MAPPED, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.MAPPED, 1232896},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public boolean mAligned;
+
+ enum MyBufferType {
+ DIRECT,
+ HEAP,
+ MAPPED
+ }
+
+ @Parameterized.Parameter(1)
+ public MyBufferType mSrcBufferType;
+
+ @Parameterized.Parameter(2)
+ public MyBufferType mDataBufferType;
+
+ @Parameterized.Parameter(3)
+ public int mBufferSize;
+
+ public static ByteBuffer newBuffer(boolean aligned, MyBufferType bufferType, int bsize)
+ throws IOException {
+ int size = aligned ? bsize : bsize + 8 + 1;
+ ByteBuffer result = null;
+ switch (bufferType) {
+ case DIRECT:
+ result = ByteBuffer.allocateDirect(size);
+ break;
+ case HEAP:
+ result = ByteBuffer.allocate(size);
+ break;
+ case MAPPED:
+ File tmpFile = File.createTempFile("MappedByteBufferTest", ".tmp");
+ tmpFile.createNewFile();
+ tmpFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw");
+ raf.setLength(size);
+ FileChannel fc = raf.getChannel();
+ result = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
+ break;
+ }
+ result.position(aligned ? 0 : 1);
+ return result;
+ }
+
+ @Test
+ public void timeByteBuffer_putByteBuffer() throws Exception {
+ ByteBuffer src = ByteBufferBulkPerfTest.newBuffer(mAligned, mSrcBufferType, mBufferSize);
+ ByteBuffer data = ByteBufferBulkPerfTest.newBuffer(mAligned, mDataBufferType, mBufferSize);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ data.position(mAligned ? 0 : 1);
+ src.put(data);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
new file mode 100644
index 000000000000..4bd7c4e4fa82
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum MyByteOrder {
+ BIG(ByteOrder.BIG_ENDIAN),
+ LITTLE(ByteOrder.LITTLE_ENDIAN);
+ final ByteOrder mByteOrder;
+
+ MyByteOrder(ByteOrder mByteOrder) {
+ this.mByteOrder = mByteOrder;
+ }
+ }
+
+ @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {MyByteOrder.BIG, true, MyBufferType.DIRECT},
+ {MyByteOrder.LITTLE, true, MyBufferType.DIRECT},
+ {MyByteOrder.BIG, false, MyBufferType.DIRECT},
+ {MyByteOrder.LITTLE, false, MyBufferType.DIRECT},
+ {MyByteOrder.BIG, true, MyBufferType.HEAP},
+ {MyByteOrder.LITTLE, true, MyBufferType.HEAP},
+ {MyByteOrder.BIG, false, MyBufferType.HEAP},
+ {MyByteOrder.LITTLE, false, MyBufferType.HEAP},
+ {MyByteOrder.BIG, true, MyBufferType.MAPPED},
+ {MyByteOrder.LITTLE, true, MyBufferType.MAPPED},
+ {MyByteOrder.BIG, false, MyBufferType.MAPPED},
+ {MyByteOrder.LITTLE, false, MyBufferType.MAPPED}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public MyByteOrder mByteOrder;
+
+ @Parameterized.Parameter(1)
+ public boolean mAligned;
+
+ enum MyBufferType {
+ DIRECT,
+ HEAP,
+ MAPPED;
+ }
+
+ @Parameterized.Parameter(2)
+ public MyBufferType mBufferType;
+
+ public static ByteBuffer newBuffer(
+ MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws IOException {
+ int size = aligned ? 8192 : 8192 + 8 + 1;
+ ByteBuffer result = null;
+ switch (bufferType) {
+ case DIRECT:
+ result = ByteBuffer.allocateDirect(size);
+ break;
+ case HEAP:
+ result = ByteBuffer.allocate(size);
+ break;
+ case MAPPED:
+ File tmpFile = new File("/sdcard/bm.tmp");
+ if (new File("/tmp").isDirectory()) {
+ // We're running on the desktop.
+ tmpFile = File.createTempFile("MappedByteBufferTest", ".tmp");
+ }
+ tmpFile.createNewFile();
+ tmpFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw");
+ raf.setLength(8192 * 8);
+ FileChannel fc = raf.getChannel();
+ result = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
+ break;
+ }
+ result.order(byteOrder.mByteOrder);
+ result.position(aligned ? 0 : 1);
+ return result;
+ }
+
+ //
+ // peeking
+ //
+
+ @Test
+ public void timeByteBuffer_getByte() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.get();
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getByteArray() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ byte[] dst = new byte[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getByte_indexed() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.get(i);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getChar() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getChar();
+ }
+ }
+ }
+
+ @Test
+ public void timeCharBuffer_getCharArray() throws Exception {
+ CharBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer();
+ char[] dst = new char[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getChar_indexed() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getChar(i * 2);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getDouble() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getDouble();
+ }
+ }
+ }
+
+ @Test
+ public void timeDoubleBuffer_getDoubleArray() throws Exception {
+ DoubleBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer();
+ double[] dst = new double[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getFloat() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getFloat();
+ }
+ }
+ }
+
+ @Test
+ public void timeFloatBuffer_getFloatArray() throws Exception {
+ FloatBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer();
+ float[] dst = new float[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getInt() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getInt();
+ }
+ }
+ }
+
+ @Test
+ public void timeIntBuffer_getIntArray() throws Exception {
+ IntBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer();
+ int[] dst = new int[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getLong() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getLong();
+ }
+ }
+ }
+
+ @Test
+ public void timeLongBuffer_getLongArray() throws Exception {
+ LongBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer();
+ long[] dst = new long[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getShort() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getShort();
+ }
+ }
+ }
+
+ @Test
+ public void timeShortBuffer_getShortArray() throws Exception {
+ ShortBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer();
+ short[] dst = new short[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ //
+ // poking
+ //
+
+ @Test
+ public void timeByteBuffer_putByte() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(0);
+ for (int i = 0; i < 1024; ++i) {
+ src.put((byte) 0);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putByteArray() throws Exception {
+ ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ byte[] src = new byte[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(mAligned ? 0 : 1);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putChar() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putChar(' ');
+ }
+ }
+ }
+
+ @Test
+ public void timeCharBuffer_putCharArray() throws Exception {
+ CharBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer();
+ char[] src = new char[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putDouble() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putDouble(0.0);
+ }
+ }
+ }
+
+ @Test
+ public void timeDoubleBuffer_putDoubleArray() throws Exception {
+ DoubleBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer();
+ double[] src = new double[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putFloat() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putFloat(0.0f);
+ }
+ }
+ }
+
+ @Test
+ public void timeFloatBuffer_putFloatArray() throws Exception {
+ FloatBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer();
+ float[] src = new float[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putInt() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putInt(0);
+ }
+ }
+ }
+
+ @Test
+ public void timeIntBuffer_putIntArray() throws Exception {
+ IntBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer();
+ int[] src = new int[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putLong() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putLong(0L);
+ }
+ }
+ }
+
+ @Test
+ public void timeLongBuffer_putLongArray() throws Exception {
+ LongBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer();
+ long[] src = new long[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putShort() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putShort((short) 0);
+ }
+ }
+ }
+
+ @Test
+ public void timeShortBuffer_putShortArray() throws Exception {
+ ShortBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer();
+ short[] src = new short[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void time_new_byteArray() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ byte[] bs = new byte[8192];
+ }
+ }
+
+ @Test
+ public void time_ByteBuffer_allocate() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ByteBuffer bs = ByteBuffer.allocate(8192);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
new file mode 100644
index 000000000000..81f9e59f2423
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferScalarVersusVectorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ }
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public ByteBufferPerfTest.MyByteOrder mByteOrder;
+
+ @Parameterized.Parameter(1)
+ public boolean mAligned;
+
+ @Parameterized.Parameter(2)
+ public ByteBufferPerfTest.MyBufferType mBufferType;
+
+ @Test
+ public void timeManualByteBufferCopy() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(0);
+ dst.position(0);
+ for (int i = 0; i < 8192; ++i) {
+ dst.put(src.get());
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBufferBulkGet() throws Exception {
+ ByteBuffer src = ByteBuffer.allocate(mAligned ? 8192 : 8192 + 1);
+ byte[] dst = new byte[8192];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst, 0, dst.length);
+ }
+ }
+
+ @Test
+ public void timeDirectByteBufferBulkGet() throws Exception {
+ ByteBuffer src = ByteBuffer.allocateDirect(mAligned ? 8192 : 8192 + 1);
+ byte[] dst = new byte[8192];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst, 0, dst.length);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
new file mode 100644
index 000000000000..28ec6ded3c86
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Tests various Character methods, intended for testing multiple implementations against each
+ * other.
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharacterPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mCharacterSet({0}), mOverload({1})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {CharacterSet.ASCII, Overload.CHAR},
+ {CharacterSet.ASCII, Overload.INT},
+ {CharacterSet.UNICODE, Overload.CHAR},
+ {CharacterSet.UNICODE, Overload.INT}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public CharacterSet mCharacterSet;
+
+ @Parameterized.Parameter(1)
+ public Overload mOverload;
+
+ private char[] mChars;
+
+ @Before
+ public void setUp() throws Exception {
+ this.mChars = mCharacterSet.mChars;
+ }
+
+ public enum Overload {
+ CHAR,
+ INT
+ }
+
+ public double nanosToUnits(double nanos) {
+ return nanos / 65536;
+ }
+
+ public enum CharacterSet {
+ ASCII(128),
+ UNICODE(65536);
+ final char[] mChars;
+
+ CharacterSet(int size) {
+ this.mChars = new char[65536];
+ for (int i = 0; i < 65536; ++i) {
+ mChars[i] = (char) (i % size);
+ }
+ }
+ }
+
+ // A fake benchmark to give us a baseline.
+ @Test
+ public void timeIsSpace() {
+ boolean fake = false;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ fake ^= ((char) ch == ' ');
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ fake ^= (ch == ' ');
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.digit(mChars[ch], 10);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.digit((int) mChars[ch], 10);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeGetNumericValue() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.getNumericValue(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.getNumericValue((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isDigit(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isDigit((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsIdentifierIgnorable() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isIdentifierIgnorable(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isIdentifierIgnorable((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsJavaIdentifierPart() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierPart(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierPart((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsJavaIdentifierStart() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierStart(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierStart((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLetter() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetter(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetter((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLetterOrDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetterOrDigit(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetterOrDigit((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLowerCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLowerCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLowerCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsSpaceChar() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isSpaceChar(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isSpaceChar((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsUpperCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isUpperCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isUpperCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsWhitespace() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isWhitespace(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isWhitespace((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeToLowerCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toLowerCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toLowerCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeToUpperCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toUpperCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toUpperCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
new file mode 100644
index 000000000000..603b182e7c36
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharsetForNamePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameters(name = "mCharsetName({0})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {"UTF-16"},
+ {"UTF-8"},
+ {"UTF8"},
+ {"ISO-8859-1"},
+ {"8859_1"},
+ {"ISO-8859-2"},
+ {"8859_2"},
+ {"US-ASCII"},
+ {"ASCII"},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public String mCharsetName;
+
+ @Test
+ public void timeCharsetForName() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Charset.forName(mCharsetName);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
new file mode 100644
index 000000000000..437d186834e0
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharsetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mLength({0}), mName({1})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {1, "UTF-16"},
+ {1, "UTF-8"},
+ {1, "UTF8"},
+ {1, "ISO-8859-1"},
+ {1, "8859_1"},
+ {1, "ISO-8859-2"},
+ {1, "8859_2"},
+ {1, "US-ASCII"},
+ {1, "ASCII"},
+ {10, "UTF-16"},
+ {10, "UTF-8"},
+ {10, "UTF8"},
+ {10, "ISO-8859-1"},
+ {10, "8859_1"},
+ {10, "ISO-8859-2"},
+ {10, "8859_2"},
+ {10, "US-ASCII"},
+ {10, "ASCII"},
+ {100, "UTF-16"},
+ {100, "UTF-8"},
+ {100, "UTF8"},
+ {100, "ISO-8859-1"},
+ {100, "8859_1"},
+ {100, "ISO-8859-2"},
+ {100, "8859_2"},
+ {100, "US-ASCII"},
+ {100, "ASCII"},
+ {1000, "UTF-16"},
+ {1000, "UTF-8"},
+ {1000, "UTF8"},
+ {1000, "ISO-8859-1"},
+ {1000, "8859_1"},
+ {1000, "ISO-8859-2"},
+ {1000, "8859_2"},
+ {1000, "US-ASCII"},
+ {1000, "ASCII"},
+ {10000, "UTF-16"},
+ {10000, "UTF-8"},
+ {10000, "UTF8"},
+ {10000, "ISO-8859-1"},
+ {10000, "8859_1"},
+ {10000, "ISO-8859-2"},
+ {10000, "8859_2"},
+ {10000, "US-ASCII"},
+ {10000, "ASCII"},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public int mLength;
+
+ @Parameterized.Parameter(1)
+ public String mName;
+
+ @Test
+ public void time_new_String_BString() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, mName);
+ }
+ }
+
+ @Test
+ public void time_new_String_BII() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, 0, bytes.length);
+ }
+ }
+
+ @Test
+ public void time_new_String_BIIString() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, 0, bytes.length, mName);
+ }
+ }
+
+ @Test
+ public void time_String_getBytes() throws Exception {
+ String string = makeString(mLength);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ string.getBytes(mName);
+ }
+ }
+
+ private static String makeString(int length) {
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ result.append('A' + (i % 26));
+ }
+ return result.toString();
+ }
+
+ private static byte[] makeBytes(String s) {
+ try {
+ return s.getBytes("US-ASCII");
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
new file mode 100644
index 000000000000..f31e9c154f15
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.libcore.regression;
+
+import android.icu.lang.UCharacter;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.charset.Charset;
+
+/**
+ * Decode the same size of ASCII, BMP, Supplementary character using fast-path UTF-8 decoder. The
+ * fast-path code is in {@link StringFactory#newStringFromBytes(byte[], int, int, Charset)}
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CharsetUtf8PerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final int mNoOfBytes = 0x100; // 4MB
+
+ private void makeUnicodeRange(int startingCodePoint, int endingCodePoint, int repeated) {
+ StringBuilder builder = new StringBuilder();
+ for (int codePoint = startingCodePoint; codePoint <= endingCodePoint; codePoint++) {
+ if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) {
+ builder.append(UCharacter.toString(codePoint));
+ }
+ }
+
+ String str = builder.toString();
+ StringBuilder builder2 = new StringBuilder();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < repeated; i++) {
+ builder2.append(str);
+ }
+ }
+ }
+
+ @Test
+ public void time_ascii() {
+ makeUnicodeRange(0, 0x7f, mNoOfBytes / 0x80);
+ }
+
+ @Test
+ public void time_bmp2() {
+ makeUnicodeRange(0x0080, 0x07ff, mNoOfBytes / 2 / 0x780);
+ }
+
+ @Test
+ public void time_bmp3() {
+ makeUnicodeRange(
+ 0x0800,
+ 0xffff,
+ mNoOfBytes / 3 / 0xf000 /* 0x10000 - 0x0800 - no of surrogate code points */);
+ }
+
+ @Test
+ public void time_supplementary() {
+ makeUnicodeRange(0x10000, 0x10ffff, mNoOfBytes / 4 / 0x100000);
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
new file mode 100644
index 000000000000..1d33fcb250b9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.zip.Adler32;
+import java.util.zip.CRC32;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ChecksumPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeAdler_block() throws Exception {
+ byte[] bytes = new byte[10000];
+ Adler32 adler = new Adler32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ adler.update(bytes);
+ }
+ }
+
+ @Test
+ public void timeAdler_byte() throws Exception {
+ Adler32 adler = new Adler32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ adler.update(1);
+ }
+ }
+
+ @Test
+ public void timeCrc_block() throws Exception {
+ byte[] bytes = new byte[10000];
+ CRC32 crc = new CRC32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ crc.update(bytes);
+ }
+ }
+
+ @Test
+ public void timeCrc_byte() throws Exception {
+ CRC32 crc = new CRC32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ crc.update(1);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
new file mode 100644
index 000000000000..35730ec753f1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/** CipherInputStream benchmark. */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CipherInputStreamPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final int DATA_SIZE = 1024 * 1024;
+ private static final byte[] DATA = new byte[DATA_SIZE];
+
+ private static final int IV_SIZE = 16;
+ private static final byte[] IV = new byte[IV_SIZE];
+
+ static {
+ for (int i = 0; i < DATA_SIZE; i++) {
+ DATA[i] = (byte) i;
+ }
+ for (int i = 0; i < IV_SIZE; i++) {
+ IV[i] = (byte) i;
+ }
+ }
+
+ private SecretKey mKey;
+
+ private byte[] mOutput = new byte[8192];
+
+ private Cipher mCipherEncrypt;
+
+ private AlgorithmParameterSpec mSpec;
+
+ @Before
+ public void setUp() throws Exception {
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ generator.init(128);
+ mKey = generator.generateKey();
+
+ mSpec = new IvParameterSpec(IV);
+
+ mCipherEncrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+ }
+
+ @Test
+ public void timeEncrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+ InputStream is = new CipherInputStream(new ByteArrayInputStream(DATA), mCipherEncrypt);
+ while (is.read(mOutput) != -1) {
+ // Keep iterating
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
new file mode 100644
index 000000000000..15c27f2366e1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Cipher benchmarks. Only runs on AES currently because of the combinatorial explosion of the test
+ * as it stands.
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class CipherPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameters(
+ name =
+ "mMode({0}), mPadding({1}), mKeySize({2}), mInputSize({3}),"
+ + " mImplementation({4})")
+ public static Collection cases() {
+ int[] mKeySizes = new int[] {128, 192, 256};
+ int[] inputSizes = new int[] {16, 32, 64, 128, 1024, 8192};
+ final List<Object[]> params = new ArrayList<>();
+ for (Mode mode : Mode.values()) {
+ for (Padding padding : Padding.values()) {
+ for (Implementation implementation : Implementation.values()) {
+ if ((mode == Mode.CBC
+ || mode == Mode.CFB
+ || mode == Mode.CTR
+ || mode == Mode.ECB
+ || mode == Mode.OFB)
+ && padding == Padding.PKCS1PADDING) {
+ continue;
+ }
+ if ((mode == Mode.CFB || mode == Mode.OFB)
+ && padding == Padding.NOPADDING
+ && implementation == Implementation.OpenSSL) {
+ continue;
+ }
+ for (int mKeySize : mKeySizes) {
+ for (int inputSize : inputSizes) {
+ params.add(
+ new Object[] {
+ mode, padding, mKeySize, inputSize, implementation
+ });
+ }
+ }
+ }
+ }
+ }
+ return params;
+ }
+
+ private static final int DATA_SIZE = 8192;
+ private static final byte[] DATA = new byte[DATA_SIZE];
+
+ private static final int IV_SIZE = 16;
+
+ private static final byte[] IV = new byte[IV_SIZE];
+
+ static {
+ for (int i = 0; i < DATA_SIZE; i++) {
+ DATA[i] = (byte) i;
+ }
+ for (int i = 0; i < IV_SIZE; i++) {
+ IV[i] = (byte) i;
+ }
+ }
+
+ public Algorithm mAlgorithm = Algorithm.AES;
+
+ public enum Algorithm {
+ AES,
+ };
+
+ @Parameterized.Parameter(0)
+ public Mode mMode;
+
+ public enum Mode {
+ CBC,
+ CFB,
+ CTR,
+ ECB,
+ OFB,
+ };
+
+ @Parameterized.Parameter(1)
+ public Padding mPadding;
+
+ public enum Padding {
+ NOPADDING,
+ PKCS1PADDING,
+ };
+
+ @Parameterized.Parameter(2)
+ public int mKeySize;
+
+ @Parameterized.Parameter(3)
+ public int mInputSize;
+
+ @Parameterized.Parameter(4)
+ public Implementation mImplementation;
+
+ public enum Implementation {
+ OpenSSL,
+ BouncyCastle
+ };
+
+ private String mProviderName;
+
+ // Key generation isn't part of the benchmark so cache the results
+ private static Map<Integer, SecretKey> sKeySizes = new HashMap<Integer, SecretKey>();
+
+ private String mCipherAlgorithm;
+ private SecretKey mKey;
+
+ private byte[] mOutput = new byte[DATA.length];
+
+ private Cipher mCipherEncrypt;
+
+ private Cipher mCipherDecrypt;
+
+ private AlgorithmParameterSpec mSpec;
+
+ @Before
+ public void setUp() throws Exception {
+ mCipherAlgorithm =
+ mAlgorithm.toString() + "/" + mMode.toString() + "/" + mPadding.toString();
+
+ String mKeyAlgorithm = mAlgorithm.toString();
+ mKey = sKeySizes.get(mKeySize);
+ if (mKey == null) {
+ KeyGenerator generator = KeyGenerator.getInstance(mKeyAlgorithm);
+ generator.init(mKeySize);
+ mKey = generator.generateKey();
+ sKeySizes.put(mKeySize, mKey);
+ }
+
+ switch (mImplementation) {
+ case OpenSSL:
+ mProviderName = "AndroidOpenSSL";
+ break;
+ case BouncyCastle:
+ mProviderName = "BC";
+ break;
+ default:
+ throw new RuntimeException(mImplementation.toString());
+ }
+
+ if (mMode != Mode.ECB) {
+ mSpec = new IvParameterSpec(IV);
+ }
+
+ mCipherEncrypt = Cipher.getInstance(mCipherAlgorithm, mProviderName);
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+
+ mCipherDecrypt = Cipher.getInstance(mCipherAlgorithm, mProviderName);
+ mCipherDecrypt.init(Cipher.DECRYPT_MODE, mKey, mSpec);
+ }
+
+ @Test
+ public void timeEncrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherEncrypt.doFinal(DATA, 0, mInputSize, mOutput);
+ }
+ }
+
+ @Test
+ public void timeDecrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherDecrypt.doFinal(DATA, 0, mInputSize, mOutput);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
new file mode 100644
index 000000000000..6728e73d0c4b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.Collator;
+import java.text.RuleBasedCollator;
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CollatorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final RuleBasedCollator COLLATOR =
+ (RuleBasedCollator) Collator.getInstance(Locale.US);
+
+ @Test
+ public void timeCollatorPrimary() {
+ COLLATOR.setStrength(Collator.PRIMARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcde", "abcdf");
+ COLLATOR.compare("abcde", "abcde");
+ COLLATOR.compare("abcdf", "abcde");
+ }
+ }
+
+ @Test
+ public void timeCollatorSecondary() {
+ COLLATOR.setStrength(Collator.SECONDARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdÂ", "abcdÄ");
+ COLLATOR.compare("abcdÂ", "abcdÂ");
+ COLLATOR.compare("abcdÄ", "abcdÂ");
+ }
+ }
+
+ @Test
+ public void timeCollatorTertiary() {
+ COLLATOR.setStrength(Collator.TERTIARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdE", "abcde");
+ COLLATOR.compare("abcde", "abcde");
+ COLLATOR.compare("abcde", "abcdE");
+ }
+ }
+
+ @Test
+ public void timeCollatorIdentical() {
+ COLLATOR.setStrength(Collator.IDENTICAL);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdȪ", "abcdȫ");
+ COLLATOR.compare("abcdȪ", "abcdȪ");
+ COLLATOR.compare("abcdȫ", "abcdȪ");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
new file mode 100644
index 000000000000..a89efffcdd1f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Random;
+import java.util.Vector;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CollectionsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mArrayListLength({0})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{4}, {16}, {64}, {256}, {1024}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int arrayListLength;
+
+ public static Comparator<Integer> REVERSE =
+ new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ int lhsAsInt = lhs.intValue();
+ int rhsAsInt = rhs.intValue();
+ return rhsAsInt < lhsAsInt ? -1 : (lhsAsInt == rhsAsInt ? 0 : 1);
+ }
+ };
+
+ @Test
+ public void timeSort_arrayList() throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input);
+ }
+ }
+
+ @Test
+ public void timeSortWithComparator_arrayList() throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ @Test
+ public void timeSort_vector() throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input);
+ }
+ }
+
+ @Test
+ public void timeSortWithComparator_vector() throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ private static <T extends List<Integer>> List<Integer> buildList(
+ int arrayListLength, Class<T> listClass) throws Exception {
+ Random random = new Random();
+ random.setSeed(0);
+ List<Integer> list = listClass.newInstance();
+ for (int i = 0; i < arrayListLength; ++i) {
+ list.add(random.nextInt());
+ }
+ return list;
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
new file mode 100644
index 000000000000..4dba1391438c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.DateFormat;
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public final class DateFormatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Locale mLocale1;
+ private Locale mLocale2;
+ private Locale mLocale3;
+ private Locale mLocale4;
+
+ @Before
+ public void setUp() throws Exception {
+ mLocale1 = Locale.TAIWAN;
+ mLocale2 = Locale.GERMANY;
+ mLocale3 = Locale.FRANCE;
+ mLocale4 = Locale.ITALY;
+ }
+
+ @Test
+ public void timeGetDateTimeInstance() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DateFormat.getDateTimeInstance();
+ }
+ }
+
+ @Test
+ public void timeGetDateTimeInstance_multiple() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale1);
+ DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale2);
+ DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale3);
+ DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale4);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
new file mode 100644
index 000000000000..f3eddab0e77c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DecimalFormatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final String EXP_PATTERN = "##E0";
+
+ private static final DecimalFormat DF = (DecimalFormat) DecimalFormat.getInstance();
+ // Keep PATTERN_INSTANCE for timing with patterns, to not dirty the plain instance.
+ private static final DecimalFormat PATTERN_INSTANCE = (DecimalFormat)
+ DecimalFormat.getInstance();
+ private static final DecimalFormat DF_CURRENCY_US = (DecimalFormat)
+ NumberFormat.getCurrencyInstance(Locale.US);
+ private static final DecimalFormat DF_CURRENCY_FR = (DecimalFormat)
+ NumberFormat.getInstance(Locale.FRANCE);
+
+ private static final BigDecimal BD10E3 = new BigDecimal("10E3");
+ private static final BigDecimal BD10E9 = new BigDecimal("10E9");
+ private static final BigDecimal BD10E100 = new BigDecimal("10E100");
+ private static final BigDecimal BD10E1000 = new BigDecimal("10E1000");
+
+ private static final int WHOLE_NUMBER = 10;
+ private static final double TWO_DP_NUMBER = 3.14;
+
+ public void formatWithGrouping(Object obj) {
+ DF.setGroupingSize(3);
+ DF.setGroupingUsed(true);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DF.format(obj);
+ }
+ }
+
+ public void format(String pattern, Object obj) {
+ PATTERN_INSTANCE.applyPattern(pattern);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ PATTERN_INSTANCE.format(obj);
+ }
+ }
+
+ public void format(Object obj) {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DF.format(obj);
+ }
+ }
+
+ public void formatToCharacterIterator(Object obj) {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DF.formatToCharacterIterator(obj);
+ }
+ }
+
+
+ public void formatCurrencyUS(Object obj) {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DF_CURRENCY_US.format(obj);
+ }
+ }
+
+ public void formatCurrencyFR(Object obj) {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DF_CURRENCY_FR.format(obj);
+ }
+ }
+
+ @Test
+ public void time_formatGrouping_BigDecimal10e3() {
+ formatWithGrouping(BD10E3);
+ }
+
+ @Test
+ public void time_formatGrouping_BigDecimal10e9() {
+ formatWithGrouping(BD10E9);
+ }
+
+ @Test
+ public void time_formatGrouping_BigDecimal10e100() {
+ formatWithGrouping(BD10E100);
+ }
+
+ @Test
+ public void time_formatGrouping_BigDecimal10e1000() {
+ formatWithGrouping(BD10E1000);
+ }
+
+ @Test
+ public void time_formatBigDecimal10e3() {
+ format(BD10E3);
+ }
+
+ @Test
+ public void time_formatBigDecimal10e9() {
+ format(BD10E9);
+ }
+
+ @Test
+ public void time_formatBigDecimal10e100() {
+ format(BD10E100);
+ }
+
+ @Test
+ public void time_formatBigDecimal10e1000() {
+ format(BD10E1000);
+ }
+
+ @Test
+ public void time_formatPi() {
+ format(Math.PI);
+ }
+
+ @Test
+ public void time_formatE() {
+ format(Math.E);
+ }
+
+ @Test
+ public void time_formatUSD() {
+ formatCurrencyUS(WHOLE_NUMBER);
+ }
+
+ @Test
+ public void time_formatUsdWithCents() {
+ formatCurrencyUS(TWO_DP_NUMBER);
+ }
+
+ @Test
+ public void time_formatEur() {
+ formatCurrencyFR(WHOLE_NUMBER);
+ }
+
+ @Test
+ public void time_formatEurWithCents() {
+ formatCurrencyFR(TWO_DP_NUMBER);
+ }
+
+ @Test
+ public void time_formatAsExponent10e3() {
+ format(EXP_PATTERN, BD10E3);
+ }
+
+ @Test
+ public void time_formatAsExponent10e9() {
+ format(EXP_PATTERN, BD10E9);
+ }
+
+ @Test
+ public void time_formatAsExponent10e100() {
+ format(EXP_PATTERN, BD10E100);
+ }
+
+ @Test
+ public void time_formatAsExponent10e1000() {
+ format(EXP_PATTERN, BD10E1000);
+ }
+
+ @Test
+ public void time_formatToCharacterIterator10e3() {
+ formatToCharacterIterator(BD10E3);
+ }
+
+ @Test
+ public void time_formatToCharacterIterator10e9() {
+ formatToCharacterIterator(BD10E9);
+ }
+
+ @Test
+ public void time_formatToCharacterIterator10e100() {
+ formatToCharacterIterator(BD10E100);
+ }
+
+ @Test
+ public void time_formatToCharacterIterator10e1000() {
+ formatToCharacterIterator(BD10E1000);
+ }
+
+ @Test
+ public void time_instantiation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new DecimalFormat();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
new file mode 100644
index 000000000000..2bf04180fa79
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DecimalFormatSymbolsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static Locale sLocale = Locale.getDefault(Locale.Category.FORMAT);
+
+ @Test
+ public void time_instantiation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new DecimalFormatSymbols(sLocale);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
new file mode 100644
index 000000000000..c3320a4e5a20
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.charset.Charset;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DefaultCharsetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void time_defaultCharset() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Charset.defaultCharset();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
new file mode 100644
index 000000000000..7c52ac424a2a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DnsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeDns() throws Exception {
+ String[] hosts = new String[] {
+ "www.amazon.com",
+ "z-ecx.images-amazon.com",
+ "g-ecx.images-amazon.com",
+ "ecx.images-amazon.com",
+ "ad.doubleclick.com",
+ "bpx.a9.com",
+ "d3dtik4dz1nej0.cloudfront.net",
+ "uac.advertising.com",
+ "servedby.advertising.com",
+ "view.atdmt.com",
+ "rmd.atdmt.com",
+ "spe.atdmt.com",
+ "www.google.com",
+ "www.cnn.com",
+ "bad.host.mtv.corp.google.com",
+ };
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ try {
+ InetAddress.getByName(hosts[++i % hosts.length]);
+ } catch (UnknownHostException ex) {
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
new file mode 100644
index 000000000000..d13335906ec6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DoPrivilegedPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeDirect() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ String lineSeparator = System.getProperty("line.separator");
+ }
+ }
+
+ @Test
+ public void timeFastAndSlow() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ String lineSeparator;
+ if (System.getSecurityManager() == null) {
+ lineSeparator = System.getProperty("line.separator");
+ } else {
+ lineSeparator = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("line.separator");
+ }
+ });
+ }
+ }
+ }
+
+ @Test
+ public void timeNewAction() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ String lineSeparator = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("line.separator");
+ }
+ });
+ }
+ }
+
+ @Test
+ public void timeReusedAction() throws Exception {
+ final PrivilegedAction<String> action = new ReusableAction("line.separator");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ String lineSeparator = AccessController.doPrivileged(action);
+ }
+ }
+
+ private static final class ReusableAction implements PrivilegedAction<String> {
+ private final String mPropertyName;
+
+ ReusableAction(String propertyName) {
+ this.mPropertyName = propertyName;
+ }
+
+ public String run() {
+ return System.getProperty(mPropertyName);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
new file mode 100644
index 000000000000..38904af7edd7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DoublePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private double mD = 1.2;
+ private long mL = 4608083138725491507L;
+
+ @Test
+ public void timeDoubleToLongBits() {
+ long result = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Double.doubleToLongBits(mD);
+ }
+ if (result != mL) {
+ throw new RuntimeException(Long.toString(result));
+ }
+ }
+
+ @Test
+ public void timeDoubleToRawLongBits() {
+ long result = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Double.doubleToRawLongBits(mD);
+ }
+ if (result != mL) {
+ throw new RuntimeException(Long.toString(result));
+ }
+ }
+
+ @Test
+ public void timeLongBitsToDouble() {
+ double result = 123.0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Double.longBitsToDouble(mL);
+ }
+ if (result != mD) {
+ throw new RuntimeException(Double.toString(result) + " "
+ + Double.doubleToRawLongBits(result));
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
new file mode 100644
index 000000000000..4ff3ba5b0aaa
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public final class EqualsHashCodePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private enum Type {
+ URI() {
+ @Override Object newInstance(String text) throws Exception {
+ return new URI(text);
+ }
+ },
+ URL() {
+ @Override Object newInstance(String text) throws Exception {
+ return new URL(text);
+ }
+ };
+ abstract Object newInstance(String text) throws Exception;
+ }
+
+ private static final String QUERY = "%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9%2C+%E0%AE%9A%E0%AF%81%E0%AE%B5%E0%AE%BE%E0%AE%B0%E0%AE%B8%E0%AF%8D%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D%2C+%E0%AE%86%E0%AE%A9%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AF%87%E0%AE%B0%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%82%E0%AE%B4%E0%AF%8D%E0%AE%A8%E0%AE%BF%E0%AE%B2%E0%AF%88+%E0%AE%8F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%8E%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%A4%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%AA%E0%AE%A3%E0%AE%BF%E0%AE%AF%E0%AF%88%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%B5%E0%AE%B2%E0%AE%BF+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%88+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%AA%E0%AF%86%E0%AE%B0%E0%AE%BF%E0%AE%AF+%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%AE%E0%AF%81%E0%AE%A4%E0%AE%B2%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%9F%E0%AE%BF%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D.+%E0%AE%85%E0%AE%A4%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%95%E0%AE%B3%E0%AF%88+%E0%AE%AA%E0%AF%86%E0%AE%B1+%E0%AE%A4%E0%AE%B5%E0%AE%BF%E0%AE%B0%2C+%E0%AE%8E%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%89%E0%AE%B4%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%89%E0%AE%9F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%AF%E0%AE%BF%E0%AE%B1%E0%AF%8D%E0%AE%9A%E0%AE%BF+%E0%AE%AE%E0%AF%87%E0%AE%B1%E0%AF%8D%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AE%A4%E0%AF%81+%E0%AE%8E%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81+%E0%AE%87%E0%AE%A4%E0%AF%81+%E0%AE%92%E0%AE%B0%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B1%E0%AE%BF%E0%AE%AF+%E0%AE%89%E0%AE%A4%E0%AE%BE%E0%AE%B0%E0%AE%A3%E0%AE%AE%E0%AF%8D%2C+%E0%AE%8E%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95.+%E0%AE%B0%E0%AE%AF%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%8E%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%B5%E0%AE%BF%E0%AE%B3%E0%AF%88%E0%AE%B5%E0%AE%BE%E0%AE%95+%E0%AE%87%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%AE%E0%AF%8D+%E0%AE%86%E0%AE%A9%E0%AF%8D%E0%AE%B2%E0%AF%88%E0%AE%A9%E0%AF%8D+%E0%AE%AA%E0%AE%AF%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%BE%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AF%87%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%AF%E0%AE%BE%E0%AE%B0%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%95%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AA%E0%AE%BF%E0%AE%9F%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AE%B0%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D.+%E0%AE%87%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%A8%E0%AE%BF%E0%AE%95%E0%AE%B4%E0%AF%8D%E0%AE%B5%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%86%E0%AE%AF%E0%AF%8D%E0%AE%A4%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%85%E0%AE%AE%E0%AF%88%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%95%E0%AE%A3%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%2C+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%B5%E0%AE%BF%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AF%81+quae+%E0%AE%AA%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AE%B1%E0%AF%88+%E0%AE%A8%E0%AF%80%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%AA%E0%AE%B0%E0%AE%BF%E0%AE%A8%E0%AF%8D%E0%AE%A4%E0%AF%81%E0%AE%B0%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%86%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%AF%E0%AE%BE%E0%AE%95+%E0%AE%AE%E0%AE%BE%E0%AE%B1%E0%AF%81%E0%AE%AE%E0%AF%8D";
+
+ @Parameterized.Parameters(name = "mType({0})")
+ public static Collection cases() {
+ final List<Object[]> params = new ArrayList<>();
+ for (Type type : Type.values()) {
+ params.add(new Object[]{type});
+ }
+ return params;
+ }
+
+ @Parameterized.Parameter(0)
+ public Type mType;
+
+ Object mA1;
+ Object mA2;
+ Object mB1;
+ Object mB2;
+
+ Object mC1;
+ Object mC2;
+
+ @Before
+ public void setUp() throws Exception {
+ mA1 = mType.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
+ mA2 = mType.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
+ mB1 = mType.newInstance("http://developer.android.com/reference/java/net/URI.html");
+ mB2 = mType.newInstance("http://developer.android.com/reference/java/net/URI.html");
+
+ mC1 = mType.newInstance("http://developer.android.com/query?q=" + QUERY);
+ // Replace the very last char.
+ mC2 = mType.newInstance("http://developer.android.com/query?q=" + QUERY.substring(0, QUERY.length() - 3) + "%AF");
+ }
+
+ @Test
+ public void timeEquals() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mA1.equals(mB1);
+ mA1.equals(mA2);
+ mB1.equals(mB2);
+ }
+ }
+
+ @Test
+ public void timeHashCode() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mA1.hashCode();
+ mB1.hashCode();
+ }
+ }
+
+ @Test
+ public void timeEqualsWithHeavilyEscapedComponent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mC1.equals(mC2);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
new file mode 100644
index 000000000000..03c9d43d3258
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.Collator;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+/**
+ * Benchmarks creation and cloning various expensive objects.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ExpensiveObjectsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeNewDateFormatTimeInstance() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
+ df.format(System.currentTimeMillis());
+ }
+ }
+
+ @Test
+ public void timeClonedDateFormatTimeInstance() {
+ DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ((DateFormat) df.clone()).format(System.currentTimeMillis());
+ }
+ }
+
+ @Test
+ public void timeReusedDateFormatTimeInstance() {
+ DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ synchronized (df) {
+ df.format(System.currentTimeMillis());
+ }
+ }
+ }
+
+ @Test
+ public void timeNewCollator() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collator.getInstance(Locale.US);
+ }
+ }
+
+ @Test
+ public void timeClonedCollator() {
+ Collator c = Collator.getInstance(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ c.clone();
+ }
+ }
+
+ @Test
+ public void timeNewDateFormatSymbols() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new DateFormatSymbols(Locale.US);
+ }
+ }
+
+ @Test
+ public void timeClonedDateFormatSymbols() {
+ DateFormatSymbols dfs = new DateFormatSymbols(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ dfs.clone();
+ }
+ }
+
+ @Test
+ public void timeNewDecimalFormatSymbols() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new DecimalFormatSymbols(Locale.US);
+ }
+ }
+
+ @Test
+ public void timeClonedDecimalFormatSymbols() {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ dfs.clone();
+ }
+ }
+
+ @Test
+ public void timeNewNumberFormat() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ NumberFormat.getInstance(Locale.US);
+ }
+ }
+
+ @Test
+ public void timeClonedNumberFormat() {
+ NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ nf.clone();
+ }
+ }
+
+ @Test
+ public void timeLongToString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Long.toString(1024L);
+ }
+ }
+
+ @Test
+ public void timeNumberFormatTrivialFormatDouble() {
+ NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ nf.format(1024.0);
+ }
+ }
+
+ @Test
+ public void timeNewSimpleDateFormat() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new SimpleDateFormat();
+ }
+ }
+
+ @Test
+ public void timeClonedSimpleDateFormat() {
+ SimpleDateFormat sdf = new SimpleDateFormat();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.clone();
+ }
+ }
+
+ @Test
+ public void timeNewGregorianCalendar() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new GregorianCalendar();
+ }
+ }
+
+ @Test
+ public void timeClonedGregorianCalendar() {
+ GregorianCalendar gc = new GregorianCalendar();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ gc.clone();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
new file mode 100644
index 000000000000..783136a5b3a2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public final class FilePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeFileCreationWithEmptyChild() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new File("/foo", "/");
+ }
+ }
+
+ @Test
+ public void timeFileCreationWithNormalizationNecessary() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new File("/foo//bar//baz//bag", "/baz/");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
new file mode 100644
index 000000000000..a995f5caa183
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class FloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private float mFloat = 1.2f;
+ private int mInt = 1067030938;
+
+ @Test
+ public void timeFloatToIntBits() {
+ int result = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Float.floatToIntBits(mFloat);
+ }
+ if (result != mInt) {
+ throw new RuntimeException(Integer.toString(result));
+ }
+ }
+
+ @Test
+ public void timeFloatToRawIntBits() {
+ int result = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Float.floatToRawIntBits(mFloat);
+ }
+ if (result != mInt) {
+ throw new RuntimeException(Integer.toString(result));
+ }
+ }
+
+ @Test
+ public void timeIntBitsToFloat() {
+ float result = 123.0f;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = Float.intBitsToFloat(mInt);
+ }
+ if (result != mFloat) {
+ throw new RuntimeException(Float.toString(result) + " "
+ + Float.floatToRawIntBits(result));
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
new file mode 100644
index 000000000000..94c4f0807cbc
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Formatter;
+import java.util.Locale;
+
+/**
+ * Compares Formatter against hand-written StringBuilder code.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class FormatterPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeFormatter_NoFormatting() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that doesn't actually need any formatting");
+ }
+ }
+
+ @Test
+ public void timeStringBuilder_NoFormatting() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("this is a reasonably short string that doesn't actually need formatting");
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneInt() {
+ Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that has an int %d in it", value);
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneIntArabic() {
+ Locale arabic = new Locale("ar");
+ Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format(arabic, "this is a reasonably short string that has an int %d in it", value);
+ }
+ }
+
+ @Test
+ public void timeStringBuilder_OneInt() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("this is a reasonably short string that has an int ");
+ sb.append(1024);
+ sb.append(" in it");
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneHexInt() {
+ Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that has an int %x in it", value);
+ }
+ }
+
+ @Test
+ public void timeStringBuilder_OneHexInt() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("this is a reasonably short string that has an int ");
+ sb.append(Integer.toHexString(1024));
+ sb.append(" in it");
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneFloat() {
+ Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that has a float %f in it", value);
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneFloat_dot2f() {
+ Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that has a float %.2f in it", value);
+ }
+ }
+
+ @Test
+ public void timeFormatter_TwoFloats() {
+ Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a short string that has two floats %f and %f in it", value, value);
+ }
+ }
+
+ @Test
+ public void timeStringBuilder_OneFloat() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("this is a reasonably short string that has a float ");
+ sb.append(10.24f);
+ sb.append(" in it");
+ }
+ }
+
+ @Test
+ public void timeFormatter_OneString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Formatter f = new Formatter();
+ f.format("this is a reasonably short string that has a string %s in it", "hello");
+ }
+ }
+
+ @Test
+ public void timeStringBuilder_OneString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("this is a reasonably short string that has a string ");
+ sb.append("hello");
+ sb.append(" in it");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
new file mode 100644
index 000000000000..5ff2b225d64f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Benchmarks creation and cloning various expensive objects.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class NumberFormatTrivialFormatLongPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeNumberFormatTrivialFormatLong() {
+ NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ nf.format(1024L);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..e7bb8f84d671
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectGetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ int mValue;
+
+ public ReflectGetFieldLittleEndianIntPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("mValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mField.getInt(this);
+ x = (int) mField.getInt(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..5bac46af4630
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectGetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ String mValue;
+
+ public ReflectGetFieldLittleEndianStringPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("mValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mField.get(this);
+ x = (String) mField.get(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..1005a70e96e0
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectGetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ static int sValue;
+
+ public ReflectGetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("sValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mField.getInt(null);
+ x = (int) mField.getInt(null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..5224ad3b5911
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectGetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ static String sValue;
+
+ public ReflectGetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("sValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mField.get(null);
+ x = (String) mField.get(null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..06696ef0773b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectSetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ int mValue;
+
+ public ReflectSetFieldLittleEndianIntPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("mValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.setInt(this, 42);
+ mField.setInt(this, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..a784c524a4c5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectSetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ String mValue;
+
+ public ReflectSetFieldLittleEndianStringPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("mValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.set(this, "qwerty");
+ mField.set(this, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..4ce0078ff1c1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectSetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ static int sValue;
+
+ public ReflectSetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("sValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.setInt(null, 42);
+ mField.setInt(null, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..587e201c4e17
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReflectSetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ static String sValue;
+
+ public ReflectSetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mField = this.getClass().getDeclaredField("sValue");
+ }
+
+ @Test
+ public void run() throws Throwable {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.set(null, "qwerty");
+ mField.set(null, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..e06b53434438
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchangeAcquire(this, mField, ~42);
+ x = (int) mVh.compareAndExchangeAcquire(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..0fd16a02e22c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchangeAcquire(this, mField, null);
+ x = (String) mVh.compareAndExchangeAcquire(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..7ad42d057588
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchangeAcquire(sField, ~42);
+ x = (int) mVh.compareAndExchangeAcquire(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..76e1f47251cf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchangeAcquire(sField, null);
+ x = (String) mVh.compareAndExchangeAcquire(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..b4b78408a45f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchange(this, mField, ~42);
+ x = (int) mVh.compareAndExchange(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..09ed167cef35
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchange(this, mField, null);
+ x = (String) mVh.compareAndExchange(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..920d2e4767e5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchangeRelease(this, mField, ~42);
+ x = (int) mVh.compareAndExchangeRelease(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..55ed789d1227
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchangeRelease(this, mField, null);
+ x = (String) mVh.compareAndExchangeRelease(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..ea3057b3f54f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchangeRelease(sField, ~42);
+ x = (int) mVh.compareAndExchangeRelease(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..20558aa92f48
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchangeRelease(sField, null);
+ x = (String) mVh.compareAndExchangeRelease(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..d7b1d2989c0e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.compareAndExchange(sField, ~42);
+ x = (int) mVh.compareAndExchange(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..d138dc979b1d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.compareAndExchange(sField, null);
+ x = (String) mVh.compareAndExchange(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..36153f2b7037
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandsetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandsetFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.compareAndSet(this, mField, ~42);
+ success = mVh.compareAndSet(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..bf4fbc4eeefb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandsetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandsetFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.compareAndSet(this, mField, null);
+ success = mVh.compareAndSet(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..d3c1b36bd3a6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.compareAndSet(sField, ~42);
+ success = mVh.compareAndSet(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..90e69a168391
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.compareAndSet(sField, null);
+ success = mVh.compareAndSet(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..96bc1049fad4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getAcquire(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAcquire(this);
+ x = (int) mVh.getAcquire(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..2679494eb6de
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetAcquireFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetAcquireFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getAcquire(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAcquire(this);
+ x = (String) mVh.getAcquire(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..170dce76d9c8
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getAcquire();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAcquire();
+ x = (int) mVh.getAcquire();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..11d12db39397
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getAcquire();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAcquire();
+ x = (String) mVh.getAcquire();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..bd2a6008e239
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetArrayLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int ELEMENT_VALUE = 42;
+ int[] mArray = {ELEMENT_VALUE};
+ VarHandle mVh;
+
+ public VarHandleGetArrayLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.arrayElementVarHandle(int[].class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.get(mArray, 0);
+ if (v != ELEMENT_VALUE) {
+ throw new RuntimeException("array element has unexpected value: " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int[] a = mArray;
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.get(a, 0);
+ x = (int) mVh.get(a, 0);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..99a09cda367f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetArrayLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String ELEMENT_VALUE = "qwerty";
+ String[] mArray = {ELEMENT_VALUE};
+ VarHandle mVh;
+
+ public VarHandleGetArrayLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.arrayElementVarHandle(String[].class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.get(mArray, 0);
+ if (v != ELEMENT_VALUE) {
+ throw new RuntimeException("array element has unexpected value: " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String[] a = mArray;
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.get(a, 0);
+ x = (String) mVh.get(a, 0);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
new file mode 100644
index 000000000000..db83606bdb54
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetByteArrayViewBigEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int VALUE = 42;
+ byte[] mArray1 = {
+ (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+ };
+ byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
+ VarHandle mVh;
+
+ public VarHandleGetByteArrayViewBigEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.get(mArray1, 0);
+ if (v != VALUE) {
+ throw new RuntimeException("array has unexpected value: " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ byte[] a = mArray1;
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.get(a, 0);
+ x = (int) mVh.get(a, 0);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..4a8f92461301
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetByteArrayViewLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int VALUE = 42;
+ byte[] mArray1 = {
+ (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+ };
+ byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
+ VarHandle mVh;
+
+ public VarHandleGetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.get(mArray1, 0);
+ if (v != VALUE) {
+ throw new RuntimeException("array has unexpected value: " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ byte[] a = mArray1;
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.get(a, 0);
+ x = (int) mVh.get(a, 0);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..4e4a9ee980fd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.get(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.get(this);
+ x = (int) mVh.get(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..3e7de1d08a0e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.get(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.get(this);
+ x = (String) mVh.get(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..67d53b34c4d6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetOpaqueFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetOpaqueFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getOpaque(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getOpaque(this);
+ x = (int) mVh.getOpaque(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..470a1ce0fb71
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetOpaqueFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetOpaqueFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getOpaque(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getOpaque(this);
+ x = (String) mVh.getOpaque(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..8a982c23b1cb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getOpaque();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getOpaque();
+ x = (int) mVh.getOpaque();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..2c17a698b5e7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getOpaque();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getOpaque();
+ x = (String) mVh.getOpaque();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..099b1f4f6d82
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.get();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.get();
+ x = (int) mVh.get();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..7f6b4b8b637e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.get();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.get();
+ x = (String) mVh.get();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..8592d30f58f0
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetVolatileFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetVolatileFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getVolatile(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getVolatile(this);
+ x = (int) mVh.getVolatile(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..539bd2aa8e8c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetVolatileFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetVolatileFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getVolatile(this);
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getVolatile(this);
+ x = (String) mVh.getVolatile(this);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..a36a7b6d39a2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Before
+ public void setup() {
+ int v = (int) mVh.getVolatile();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getVolatile();
+ x = (int) mVh.getVolatile();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..90d2a70691ad
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Before
+ public void setup() {
+ String v = (String) mVh.getVolatile();
+ if (v != FIELD_VALUE) {
+ throw new RuntimeException("field has unexpected value " + v);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getVolatile();
+ x = (String) mVh.getVolatile();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..4e5fcf32edd2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ float mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAddAcquire(this, 2.17f);
+ x = (float) mVh.getAndAddAcquire(this, 2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..fd0abf85abfc
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAddAcquire(this, ~42);
+ x = (int) mVh.getAndAddAcquire(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..9272b1164d07
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ static float sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAddAcquire(2.17f);
+ x = (float) mVh.getAndAddAcquire(2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..a896d0a8e3e7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAddAcquire(~42);
+ x = (int) mVh.getAndAddAcquire(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..671b0a3c7c83
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ float mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAdd(this, 2.17f);
+ x = (float) mVh.getAndAdd(this, 2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..1eb3f9277d56
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAdd(this, ~42);
+ x = (int) mVh.getAndAdd(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..f23d5e269154
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ float mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAddRelease(this, 2.17f);
+ x = (float) mVh.getAndAddRelease(this, 2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..161379851ce6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAddRelease(this, ~42);
+ x = (int) mVh.getAndAddRelease(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..14f1c002812f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ static float sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAddRelease(2.17f);
+ x = (float) mVh.getAndAddRelease(2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..8327caf0a124
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAddRelease(~42);
+ x = (int) mVh.getAndAddRelease(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
new file mode 100644
index 000000000000..6c211fb5371b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final float FIELD_VALUE = 3.14f;
+ static float sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", float.class);
+ }
+
+ @Test
+ public void run() {
+ float x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (float) mVh.getAndAdd(2.17f);
+ x = (float) mVh.getAndAdd(2.17f);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..d02cd735e753
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandaddStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandaddStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndAdd(~42);
+ x = (int) mVh.getAndAdd(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..0777586dadd9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
+ x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..24a949f7b73c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAndAcquire(~42);
+ x = (int) mVh.getAndBitwiseAndAcquire(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..4b94bbe5d86d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAnd(this, ~42);
+ x = (int) mVh.getAndBitwiseAnd(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..1784c0557442
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
+ x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..f85d3eeae9aa
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAndRelease(~42);
+ x = (int) mVh.getAndBitwiseAndRelease(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..81f6779e9820
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseAnd(~42);
+ x = (int) mVh.getAndBitwiseAnd(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..9436fadfde72
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
+ x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..9ebc45848003
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOrAcquire(~42);
+ x = (int) mVh.getAndBitwiseOrAcquire(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..ea159a123d21
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOr(this, ~42);
+ x = (int) mVh.getAndBitwiseOr(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..a42ec7e93c05
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
+ x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..6f1007e553cf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOrRelease(~42);
+ x = (int) mVh.getAndBitwiseOrRelease(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..6a738181104b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseOr(~42);
+ x = (int) mVh.getAndBitwiseOr(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..e9a365bd72a4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
+ x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..fc9191cc2b77
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXorAcquire(~42);
+ x = (int) mVh.getAndBitwiseXorAcquire(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..5919a1dc32c9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXor(this, ~42);
+ x = (int) mVh.getAndBitwiseXor(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..313e5806cbf7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
+ x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..9c8b3ae1b939
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXorRelease(~42);
+ x = (int) mVh.getAndBitwiseXorRelease(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..ea618cc405be
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndBitwiseXor(~42);
+ x = (int) mVh.getAndBitwiseXor(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..df6f470450ea
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSetAcquire(this, ~42);
+ x = (int) mVh.getAndSetAcquire(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..63fd7406cee4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSetAcquire(this, null);
+ x = (String) mVh.getAndSetAcquire(this, null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..a96031e673cf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSetAcquire(~42);
+ x = (int) mVh.getAndSetAcquire(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..3bc25fbbf524
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSetAcquire(null);
+ x = (String) mVh.getAndSetAcquire(null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..7ffdf11d0fa6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSet(this, ~42);
+ x = (int) mVh.getAndSet(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..cc7f3be26319
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSet(this, null);
+ x = (String) mVh.getAndSet(this, null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..8d54c00f0fe1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSetRelease(this, ~42);
+ x = (int) mVh.getAndSetRelease(this, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..22e92dd06330
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSetRelease(this, null);
+ x = (String) mVh.getAndSetRelease(this, null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..08ddc8b0227c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSetRelease(~42);
+ x = (int) mVh.getAndSetRelease(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..429e090642e9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSetRelease(null);
+ x = (String) mVh.getAndSetRelease(null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..d5b31f66cab5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (int) mVh.getAndSet(~42);
+ x = (int) mVh.getAndSet(~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..8667aaa961a4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleGetandsetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleGetandsetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x = (String) mVh.getAndSet(null);
+ x = (String) mVh.getAndSet(null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..aa202469eb93
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetArrayLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int ELEMENT_VALUE = 42;
+ int[] mArray = {ELEMENT_VALUE};
+ VarHandle mVh;
+
+ public VarHandleSetArrayLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.arrayElementVarHandle(int[].class);
+ }
+
+ @After
+ public void teardown() {
+ if (mArray[0] != ~42) {
+ throw new RuntimeException("array element has unexpected value: " + mArray[0]);
+ }
+ }
+
+ @Test
+ public void run() {
+ int[] a = mArray;
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(a, 0, ~42);
+ mVh.set(a, 0, ~42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..9e0210fbd72c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetArrayLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String ELEMENT_VALUE = "qwerty";
+ String[] mArray = {ELEMENT_VALUE};
+ VarHandle mVh;
+
+ public VarHandleSetArrayLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.arrayElementVarHandle(String[].class);
+ }
+
+ @After
+ public void teardown() {
+ if (mArray[0] != null) {
+ throw new RuntimeException("array element has unexpected value: " + mArray[0]);
+ }
+ }
+
+ @Test
+ public void run() {
+ String[] a = mArray;
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(a, 0, null);
+ mVh.set(a, 0, null);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
new file mode 100644
index 000000000000..d48916886341
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetByteArrayViewBigEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int VALUE = 42;
+ byte[] mArray1 = {
+ (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+ };
+ byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
+ VarHandle mVh;
+
+ public VarHandleSetByteArrayViewBigEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
+ }
+
+ @After
+ public void teardown() {
+ if (!Arrays.equals(mArray2, mArray1)) {
+ throw new RuntimeException(
+ "array has unexpected values: "
+ + mArray2[0]
+ + " "
+ + mArray2[1]
+ + " "
+ + mArray2[2]
+ + " "
+ + mArray2[3]);
+ }
+ }
+
+ @Test
+ public void run() {
+ byte[] a = mArray2;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(a, 0, VALUE);
+ mVh.set(a, 0, VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..b06d7eff199d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetByteArrayViewLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int VALUE = 42;
+ byte[] mArray1 = {
+ (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+ };
+ byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
+ VarHandle mVh;
+
+ public VarHandleSetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @After
+ public void teardown() {
+ if (!Arrays.equals(mArray2, mArray1)) {
+ throw new RuntimeException(
+ "array has unexpected values: "
+ + mArray2[0]
+ + " "
+ + mArray2[1]
+ + " "
+ + mArray2[2]
+ + " "
+ + mArray2[3]);
+ }
+ }
+
+ @Test
+ public void run() {
+ byte[] a = mArray2;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(a, 0, VALUE);
+ mVh.set(a, 0, VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..84469375c7e2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(this, FIELD_VALUE);
+ mVh.set(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..34540a31ad78
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(this, FIELD_VALUE);
+ mVh.set(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..c79b5133afd5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetOpaqueFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetOpaqueFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setOpaque(this, FIELD_VALUE);
+ mVh.setOpaque(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..028130ddef96
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetOpaqueFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetOpaqueFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setOpaque(this, FIELD_VALUE);
+ mVh.setOpaque(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..06a5a8ce8ceb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setOpaque(FIELD_VALUE);
+ mVh.setOpaque(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..78eefc89c8fd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setOpaque(FIELD_VALUE);
+ mVh.setOpaque(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..cd1bd4824175
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setRelease(this, FIELD_VALUE);
+ mVh.setRelease(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..6c0740c7169e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetReleaseFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetReleaseFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setRelease(this, FIELD_VALUE);
+ mVh.setRelease(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..b95f24b0a1e8
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setRelease(FIELD_VALUE);
+ mVh.setRelease(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..b03cf826c7f4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setRelease(FIELD_VALUE);
+ mVh.setRelease(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..c98c09274102
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(FIELD_VALUE);
+ mVh.set(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..625cfc77e15b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.set(FIELD_VALUE);
+ mVh.set(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..58319b3f6326
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetVolatileFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetVolatileFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setVolatile(this, FIELD_VALUE);
+ mVh.setVolatile(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..f741542411f5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetVolatileFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetVolatileFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (mField != FIELD_VALUE) {
+ throw new RuntimeException("mField has unexpected value " + mField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setVolatile(this, FIELD_VALUE);
+ mVh.setVolatile(this, FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..87f6a7832526
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ int x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setVolatile(FIELD_VALUE);
+ mVh.setVolatile(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..610345f69051
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @After
+ public void teardown() {
+ if (sField != FIELD_VALUE) {
+ throw new RuntimeException("sField has unexpected value " + sField);
+ }
+ }
+
+ @Test
+ public void run() {
+ String x;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mVh.setVolatile(FIELD_VALUE);
+ mVh.setVolatile(FIELD_VALUE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..519d4fd6179b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetAcquire(this, mField, ~42);
+ success = mVh.weakCompareAndSetAcquire(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..322cf639e81d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetAcquire(this, mField, null);
+ success = mVh.weakCompareAndSetAcquire(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..f8ccbadf682f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetAcquire(sField, ~42);
+ success = mVh.weakCompareAndSetAcquire(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..16f1059d150f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetAcquire(sField, null);
+ success = mVh.weakCompareAndSetAcquire(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..c7084fe63b06
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSet(this, mField, ~42);
+ success = mVh.weakCompareAndSet(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..9d526b8687ca
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSet(this, mField, null);
+ success = mVh.weakCompareAndSet(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..8372f6ccffbb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetPlain(this, mField, ~42);
+ success = mVh.weakCompareAndSetPlain(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..87e47e76984f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetPlain(this, mField, null);
+ success = mVh.weakCompareAndSetPlain(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..aa2e1049e302
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetPlain(sField, ~42);
+ success = mVh.weakCompareAndSetPlain(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..ebaa0801e894
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetPlain(sField, null);
+ success = mVh.weakCompareAndSetPlain(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..d90356a02fa6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ int mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetRelease(this, mField, ~42);
+ success = mVh.weakCompareAndSetRelease(this, mField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..6db995a7fd0b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ String mField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findVarHandle(this.getClass(), "mField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetRelease(this, mField, null);
+ success = mVh.weakCompareAndSetRelease(this, mField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..ecea19e2036a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetRelease(sField, ~42);
+ success = mVh.weakCompareAndSetRelease(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..ab86284729c2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSetRelease(sField, null);
+ success = mVh.weakCompareAndSetRelease(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
new file mode 100644
index 000000000000..23a33f54fcb9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final int FIELD_VALUE = 42;
+ static int sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", int.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSet(sField, ~42);
+ success = mVh.weakCompareAndSet(sField, 42);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
new file mode 100644
index 000000000000..270b5adccde1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+// This file is generated by generate_java.py do not directly modify!
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final String FIELD_VALUE = "qwerty";
+ static String sField = FIELD_VALUE;
+ VarHandle mVh;
+
+ public VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
+ }
+
+ @Test
+ public void run() {
+ boolean success;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ success = mVh.weakCompareAndSet(sField, null);
+ success = mVh.weakCompareAndSet(sField, "qwerty");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
new file mode 100755
index 000000000000..f3a1fff52205
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
@@ -0,0 +1,515 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2022 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.
+
+"""
+Generate java benchmarks for varhandles.
+Adapted to use CrystalBall from art/test/2239-varhandle-perf/util-src/generate_java.py.
+
+To run use: python generate_java.py <destination_directory>
+
+And then to correct lint errors (from frameworks/base):
+../../tools/repohooks/tools/google-java-format.py --fix --sort-imports --google-java-format-diff ../../external/google-java-format/scripts/google-java-format-diff.py
+"""
+
+
+from enum import Enum
+from pathlib import Path
+
+import io
+import sys
+
+
+class MemLoc(Enum):
+ FIELD = 0
+ ARRAY = 1
+ BYTE_ARRAY_VIEW = 2
+
+
+def to_camel_case(word):
+ return ''.join(c for c in word.title() if not c == '_')
+
+
+LOOP ="BenchmarkState state = mPerfStatusReporter.getBenchmarkState();\n while (state.keepRunning())"
+
+class Benchmark:
+ def __init__(self, code, static, vartype, flavour, klass, method, memloc,
+ byteorder="LITTLE_ENDIAN"):
+ self.code = code
+ self.static = static
+ self.vartype = vartype
+ self.flavour = flavour
+ self.klass = klass
+ self.method = method
+ self.byteorder = byteorder
+ self.memloc = memloc
+
+ def fullname(self):
+ return "{klass}{method}{flavour}{static_name}{memloc}{byteorder}{vartype}PerfTest".format(
+ klass = self.klass,
+ method = to_camel_case(self.method),
+ flavour = self.flavour,
+ static_name = "Static" if self.static else "",
+ memloc = to_camel_case(self.memloc.name),
+ byteorder = to_camel_case(self.byteorder),
+ vartype = to_camel_case(self.vartype))
+
+ def gencode(self):
+ if self.klass == "Reflect":
+ method_suffix = "" if self.vartype == "String" else self.vartype.title()
+ static_first_arg = "null"
+ elif self.klass == "Unsafe":
+ method_suffix = "Object" if self.vartype == "String" else self.vartype.title()
+ static_first_arg = "this.getClass()"
+ else:
+ method_suffix = ""
+ static_first_arg = ""
+
+ first_arg = static_first_arg if self.static else "this"
+
+ return self.code.format(
+ name = self.fullname(),
+ method = self.method + method_suffix,
+ flavour = self.flavour,
+ static_name = "Static" if self.static else "",
+ static_kwd = "static " if self.static else "",
+ static_prefix = "s" if self.static else "m",
+ this = first_arg,
+ this_comma = "" if not first_arg else first_arg + ", ",
+ vartype = self.vartype,
+ byteorder = self.byteorder,
+ value1 = VALUES[self.vartype][0],
+ value2 = VALUES[self.vartype][1],
+ value1_byte_array = VALUES["byte[]"][self.byteorder][0],
+ value2_byte_array = VALUES["byte[]"][self.byteorder][1],
+ loop = LOOP)
+
+
+def BenchVHField(code, static, vartype, flavour, method):
+ return Benchmark(code, static, vartype, flavour, "VarHandle", method, MemLoc.FIELD)
+
+
+def BenchVHArray(code, vartype, flavour, method):
+ return Benchmark(code, False, vartype, flavour, "VarHandle", method, MemLoc.ARRAY)
+
+
+def BenchVHByteArrayView(code, byteorder, vartype, flavour, method):
+ return Benchmark(code, False, vartype, flavour, "VarHandle", method, MemLoc.BYTE_ARRAY_VIEW, byteorder)
+
+
+def BenchReflect(code, static, vartype, method):
+ return Benchmark(code, static, vartype, "", "Reflect", method, MemLoc.FIELD)
+
+
+def BenchUnsafe(code, static, vartype, method):
+ return Benchmark(code, static, vartype, "", "Unsafe", method, MemLoc.FIELD)
+
+
+VALUES = {
+ "int": ["42", "~42"],
+ "float": ["3.14f", "2.17f"],
+ "String": ["\"qwerty\"", "null"],
+ "byte[]": {
+ "LITTLE_ENDIAN": [
+ "{ (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24) }",
+ "{ (byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24) }",
+ ],
+ "BIG_ENDIAN": [
+ "{ (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE }",
+ "{ (byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE }",
+ ],
+ },
+}
+
+REPEAT = 2
+REPEAT_HALF = (int) (REPEAT / 2)
+
+
+BANNER = """/*
+ * Copyright (C) 2022 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.
+ */
+ // This file is generated by generate_java.py do not directly modify!"""
+
+
+VH_IMPORTS = """
+package android.libcore.varhandles;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+"""
+
+
+VH_START = BANNER + VH_IMPORTS + """
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class {name} {{
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final {vartype} FIELD_VALUE = {value1};
+ {static_kwd}{vartype} {static_prefix}Field = FIELD_VALUE;
+ VarHandle mVh;
+
+ public {name}() throws Throwable {{
+ mVh = MethodHandles.lookup().find{static_name}VarHandle(this.getClass(), "{static_prefix}Field", {vartype}.class);
+ }}
+"""
+
+
+END = """
+ }}
+ }}
+}}"""
+
+
+VH_GET = VH_START + """
+ @Before
+ public void setup() {{
+ {vartype} v = ({vartype}) mVh.{method}{flavour}({this});
+ if (v != FIELD_VALUE) {{
+ throw new RuntimeException("field has unexpected value " + v);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}({this});""" * REPEAT + END
+
+
+VH_SET = VH_START + """
+ @After
+ public void teardown() {{
+ if ({static_prefix}Field != FIELD_VALUE) {{
+ throw new RuntimeException("{static_prefix}Field has unexpected value " + {static_prefix}Field);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ {vartype} x;
+ {loop} {{""" + """
+ mVh.{method}{flavour}({this_comma}FIELD_VALUE);""" * REPEAT + END
+
+
+VH_CAS = VH_START + """
+ @Test
+ public void run() {{
+ boolean success;
+ {loop} {{""" + """
+ success = mVh.{method}{flavour}({this_comma}{static_prefix}Field, {value2});
+ success = mVh.{method}{flavour}({this_comma}{static_prefix}Field, {value1});""" * REPEAT_HALF + END
+
+
+VH_CAE = VH_START + """
+ @Test
+ public void run() {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}({this_comma}{static_prefix}Field, {value2});
+ x = ({vartype}) mVh.{method}{flavour}({this_comma}{static_prefix}Field, {value1});""" * REPEAT_HALF + END
+
+
+VH_GAS = VH_START + """
+ @Test
+ public void run() {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}({this_comma}{value2});""" * REPEAT + END
+
+
+VH_GAA = VH_START + """
+ @Test
+ public void run() {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}({this_comma}{value2});""" * REPEAT + END
+
+
+VH_GAB = VH_START + """
+ @Test
+ public void run() {{
+ int x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}({this_comma}{value2});""" * REPEAT + END
+
+
+VH_START_ARRAY = BANNER + VH_IMPORTS + """
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class {name} {{
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final {vartype} ELEMENT_VALUE = {value1};
+ {vartype}[] mArray = {{ ELEMENT_VALUE }};
+ VarHandle mVh;
+
+ public {name}() throws Throwable {{
+ mVh = MethodHandles.arrayElementVarHandle({vartype}[].class);
+ }}
+"""
+
+
+VH_GET_A = VH_START_ARRAY + """
+ @Before
+ public void setup() {{
+ {vartype} v = ({vartype}) mVh.{method}{flavour}(mArray, 0);
+ if (v != ELEMENT_VALUE) {{
+ throw new RuntimeException("array element has unexpected value: " + v);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ {vartype}[] a = mArray;
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}(a, 0);""" * REPEAT + END
+
+
+VH_SET_A = VH_START_ARRAY + """
+ @After
+ public void teardown() {{
+ if (mArray[0] != {value2}) {{
+ throw new RuntimeException("array element has unexpected value: " + mArray[0]);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ {vartype}[] a = mArray;
+ {vartype} x;
+ {loop} {{""" + """
+ mVh.{method}{flavour}(a, 0, {value2});""" * REPEAT + END
+
+
+VH_START_BYTE_ARRAY_VIEW = BANNER + VH_IMPORTS + """
+import java.util.Arrays;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class {name} {{
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ static final {vartype} VALUE = {value1};
+ byte[] mArray1 = {value1_byte_array};
+ byte[] mArray2 = {value2_byte_array};
+ VarHandle mVh;
+
+ public {name}() throws Throwable {{
+ mVh = MethodHandles.byteArrayViewVarHandle({vartype}[].class, ByteOrder.{byteorder});
+ }}
+"""
+
+
+VH_GET_BAV = VH_START_BYTE_ARRAY_VIEW + """
+ @Before
+ public void setup() {{
+ {vartype} v = ({vartype}) mVh.{method}{flavour}(mArray1, 0);
+ if (v != VALUE) {{
+ throw new RuntimeException("array has unexpected value: " + v);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ byte[] a = mArray1;
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mVh.{method}{flavour}(a, 0);""" * REPEAT + END
+
+
+VH_SET_BAV = VH_START_BYTE_ARRAY_VIEW + """
+ @After
+ public void teardown() {{
+ if (!Arrays.equals(mArray2, mArray1)) {{
+ throw new RuntimeException("array has unexpected values: " +
+ mArray2[0] + " " + mArray2[1] + " " + mArray2[2] + " " + mArray2[3]);
+ }}
+ }}
+
+ @Test
+ public void run() {{
+ byte[] a = mArray2;
+ {loop} {{""" + """
+ mVh.{method}{flavour}(a, 0, VALUE);""" * REPEAT + END
+
+
+REFLECT_START = BANNER + VH_IMPORTS + """
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class {name} {{
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ Field mField;
+ {static_kwd}{vartype} {static_prefix}Value;
+
+ public {name}() throws Throwable {{
+ mField = this.getClass().getDeclaredField("{static_prefix}Value");
+ }}
+"""
+
+
+REFLECT_GET = REFLECT_START + """
+ @Test
+ public void run() throws Throwable {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) mField.{method}({this});""" * REPEAT + END
+
+
+REFLECT_SET = REFLECT_START + """
+ @Test
+ public void run() throws Throwable {{
+ {loop} {{""" + """
+ mField.{method}({this_comma}{value1});""" * REPEAT + END
+
+
+UNSAFE_START = BANNER + VH_IMPORTS + """
+import java.lang.reflect.Field;
+import jdk.internal.misc.Unsafe;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class {name} {{
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ long mOffset;
+ public {static_kwd}{vartype} {static_prefix}Value = {value1};
+
+ {name}() throws Throwable {{
+ Field field = this.getClass().getDeclaredField("{static_prefix}Value");
+ mOffset = get{static_name}FieldOffset(field);
+ }}
+"""
+
+
+UNSAFE_GET = UNSAFE_START + """
+ @Test
+ public void run() throws Throwable {{
+ {vartype} x;
+ {loop} {{""" + """
+ x = ({vartype}) theUnsafe.{method}({this_comma}mOffset);""" * REPEAT + END
+
+
+UNSAFE_PUT = UNSAFE_START + """
+ @Test
+ public void run() throws Throwable {{
+ {loop} {{""" + """
+ theUnsafe.{method}({this_comma}mOffset, {value1});""" * REPEAT + END
+
+
+UNSAFE_CAS = UNSAFE_START + """
+ @Test
+ public void run() throws Throwable {{
+ {loop} {{""" + """
+ theUnsafe.{method}({this_comma}mOffset, {value1}, {value2});
+ theUnsafe.{method}({this_comma}mOffset, {value2}, {value1});""" * REPEAT_HALF + END
+
+
+ALL_BENCHMARKS = (
+ [BenchVHField(VH_GET, static, vartype, flavour, "get")
+ for flavour in ["", "Acquire", "Opaque", "Volatile"]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_SET, static, vartype, flavour, "set")
+ for flavour in ["", "Volatile", "Opaque", "Release"]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_CAS, static, vartype, flavour, "compareAndSet")
+ for flavour in [""]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_CAS, static, vartype, flavour, "weakCompareAndSet")
+ for flavour in ["", "Plain", "Acquire", "Release"]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_CAE, static, vartype, flavour, "compareAndExchange")
+ for flavour in ["", "Acquire", "Release"]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_GAS, static, vartype, flavour, "getAndSet")
+ for flavour in ["", "Acquire", "Release"]
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchVHField(VH_GAA, static, vartype, flavour, "getAndAdd")
+ for flavour in ["", "Acquire", "Release"]
+ for static in [True, False]
+ for vartype in ["int", "float"]] +
+ [BenchVHField(VH_GAB, static, vartype, flavour, "getAndBitwise")
+ for flavour in [oper + mode
+ for oper in ["Or", "Xor", "And"]
+ for mode in ["", "Acquire", "Release"]]
+ for static in [True, False]
+ for vartype in ["int"]] +
+ [BenchVHArray(VH_GET_A, vartype, flavour, "get")
+ for flavour in [""]
+ for vartype in ["int", "String"]] +
+ [BenchVHArray(VH_SET_A, vartype, flavour, "set")
+ for flavour in [""]
+ for vartype in ["int", "String"]] +
+ [BenchVHByteArrayView(VH_GET_BAV, byteorder, vartype, flavour, "get")
+ for flavour in [""]
+ for byteorder in ["BIG_ENDIAN", "LITTLE_ENDIAN"]
+ for vartype in ["int"]] +
+ [BenchVHByteArrayView(VH_SET_BAV, byteorder, vartype, flavour, "set")
+ for flavour in [""]
+ for byteorder in ["BIG_ENDIAN", "LITTLE_ENDIAN"]
+ for vartype in ["int"]] +
+ [BenchReflect(REFLECT_GET, static, vartype, "get")
+ for static in [True, False]
+ for vartype in ["int", "String"]] +
+ [BenchReflect(REFLECT_SET, static, vartype, "set")
+ for static in [True, False]
+ for vartype in ["int", "String"]])
+
+
+
+def main(argv):
+ final_java_dir = Path(argv[1])
+ if not final_java_dir.exists() or not final_java_dir.is_dir():
+ print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr)
+ sys.exit(1)
+
+ for bench in ALL_BENCHMARKS:
+ file_path = final_java_dir / "{}.java".format(bench.fullname())
+ with file_path.open("w") as f:
+ print(bench.gencode(), file=f)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java
new file mode 100644
index 000000000000..898111f2fd8a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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.text;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.PerfTestActivity;
+import android.platform.test.annotations.LargeTest;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.widget.TextView;
+
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class TextViewCursorAnchorInfoPerfTest {
+ @Parameterized.Parameters(name = "mTextLength ({0}))")
+ public static Collection<Integer> data() {
+ return Arrays.asList(100, 300, 1000, 3000, 10000);
+ }
+
+ private static final int WORD_LENGTH = 9; // Random word has 9 characters.
+ private static final int WORDS_IN_LINE = 12; // Roughly, 12 words in a line.
+
+
+ private static final TextPaint PAINT = new TextPaint();
+ // The width is an estimation. There might be lines with less or more words.
+ private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
+ private static final int TEXT_HEIGHT = 1024;
+
+ @Parameterized.Parameter(0)
+ public int mTextLength;
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Rule
+ public ActivityTestRule<PerfTestActivity> mActivityTestRule = new ActivityTestRule<>(
+ PerfTestActivity.class);
+
+ private TextPerfUtils mTextUtil = new TextPerfUtils();
+ private PerfTextView mTextView;
+
+ @Before
+ public void setUp() {
+ mTextUtil.resetRandom(0 /* seed */);
+ }
+
+ public void setUpTextView() {
+ Activity activity = mActivityTestRule.getActivity();
+
+ mTextView = new PerfTextView(activity);
+
+ mTextView.setHeight(TEXT_HEIGHT);
+ mTextView.setWidth(TEXT_WIDTH);
+ final ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(TEXT_WIDTH, TEXT_HEIGHT);
+ mTextView.setLayoutParams(p);
+ activity.setContentView(mTextView);
+
+ mTextView.setText(mTextUtil.nextRandomParagraph(WORD_LENGTH, mTextLength));
+ mTextView.invalidate();
+ mTextView.mySetFrame(TEXT_WIDTH, TEXT_HEIGHT);
+ mTextView.measure(View.MeasureSpec.makeMeasureSpec(TEXT_WIDTH, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(TEXT_HEIGHT, View.MeasureSpec.EXACTLY));
+ mTextView.layout(0, 0, TEXT_WIDTH, TEXT_HEIGHT);
+ }
+
+ @Test
+ public void testPopulateCharacterBounds() throws Throwable {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ mActivityTestRule.runOnUiThread(() -> {
+ setUpTextView();
+ while (state.keepRunning()) {
+ final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+ mTextView.populateCharacterBounds(builder, 0, mTextLength, 0f, 0f);
+ }
+ });
+ }
+
+ private static class PerfTextView extends TextView {
+
+ PerfTextView(Context context) {
+ super(context);
+ }
+
+ PerfTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ PerfTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ PerfTextView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ void mySetFrame(int width, int height) {
+ super.setFrame(0, 0, width, height);
+ }
+ }
+
+}
diff --git a/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java b/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java
index 4cd974141d26..123b2eeba5dd 100644
--- a/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java
@@ -59,9 +59,10 @@ public class HandwritingInitiatorPerfTest {
public void setup() {
final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
- ViewConfiguration viewConfiguration = ViewConfiguration.get(mContext);
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(mContext);
mTouchSlop = viewConfiguration.getScaledTouchSlop();
- InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
+ final InputMethodManager inputMethodManager =
+ mContext.getSystemService(InputMethodManager.class);
mHandwritingInitiator = new HandwritingInitiator(viewConfiguration, inputMethodManager);
}
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index 67a33802f556..c061a7c96452 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -195,8 +195,7 @@ public class PackageParsingPerfTest {
// For testing, just disable enforcement to avoid hooking up to compat framework
ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
}
- val parser = ParsingPackageUtils(false,
- null,
+ val parser = ParsingPackageUtils(null,
null,
emptyList(),
object :
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index 0d17bbc7bbff..b0c295c331d7 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -24,12 +24,16 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -100,20 +104,21 @@ class BlobAccessMode {
}
boolean isAccessAllowedForCaller(Context context,
- @NonNull String callingPackage, @NonNull String committerPackage) {
+ @NonNull String callingPackage, int callingUid, int committerUid) {
if ((mAccessType & ACCESS_TYPE_PUBLIC) != 0) {
return true;
}
- final PackageManager pm = context.getPackageManager();
if ((mAccessType & ACCESS_TYPE_SAME_SIGNATURE) != 0) {
- if (pm.checkSignatures(committerPackage, callingPackage)
- == PackageManager.SIGNATURE_MATCH) {
+ if (checkSignatures(callingUid, committerUid)) {
return true;
}
}
if ((mAccessType & ACCESS_TYPE_ALLOWLIST) != 0) {
+ final UserHandle callingUser = UserHandle.of(UserHandle.getUserId(callingUid));
+ final PackageManager pm =
+ context.createContextAsUser(callingUser, 0 /* flags */).getPackageManager();
for (int i = 0; i < mAllowedPackages.size(); ++i) {
final PackageIdentifier packageIdentifier = mAllowedPackages.valueAt(i);
if (packageIdentifier.packageName.equals(callingPackage)
@@ -127,6 +132,19 @@ class BlobAccessMode {
return false;
}
+ /**
+ * Compare signatures for two packages of different users.
+ */
+ private boolean checkSignatures(int uid1, int uid2) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return LocalServices.getService(PackageManagerInternal.class)
+ .checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
int getAccessType() {
return mAccessType;
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 7638f059b47e..d5315daec11a 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -293,7 +293,7 @@ class BlobMetadata {
// Check if the caller is allowed access as per the access mode specified
// by the committer.
if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
- callingPackage, committer.packageName)) {
+ callingPackage, callingUid, committer.uid)) {
return true;
}
}
@@ -316,7 +316,7 @@ class BlobMetadata {
// Check if the caller is allowed access as per the access mode specified
// by the committer.
if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
- callingPackage, committer.packageName)) {
+ callingPackage, callingUid, committer.uid)) {
return true;
}
}
diff --git a/api/api.go b/api/api.go
index ce8cd1426661..ca0fc28cdb9d 100644
--- a/api/api.go
+++ b/api/api.go
@@ -179,7 +179,7 @@ func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) {
// Note: order matters: first parameter is the full api-versions.xml
// after that the stubs files in any order
// stubs files are all modules that export API surfaces EXCEPT ART
- props.Srcs = append([]string{":framework-doc-stubs{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
+ props.Srcs = append([]string{":api_versions_public{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
props.Dists = []android.Dist{{Targets: []string{"sdk"}}}
ctx.CreateModule(genrule.GenRuleFactory, &props)
}
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index f6199137012f..6b71e24a1d35 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -110,7 +110,6 @@ Landroid/content/pm/IPackageInstallObserver2$Stub;-><init>()V
Landroid/content/pm/IPackageInstallObserver2$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageInstallObserver2;
Landroid/content/pm/IPackageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageManager$Stub$Proxy;->checkUidPermission(Ljava/lang/String;I)I
-Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I
Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 7ff4bc4bcf76..2604497dcb63 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -425,7 +425,8 @@ public class Instrument {
if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
return cn;
} else {
- List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList();
+ List<InstrumentationInfo> infos = mPm.queryInstrumentationAsUser(
+ null, 0, userId).getList();
final int numInfos = infos == null ? 0: infos.size();
ArrayList<ComponentName> cns = new ArrayList<>();
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 50c8e933d25f..dae4570456cd 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -71,8 +71,6 @@ static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimat
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
-static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
-static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
@@ -510,7 +508,8 @@ status_t BootAnimation::readyToRun() {
resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
- resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
+ resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
+ ISurfaceComposerClient::eOpaque);
SurfaceComposerClient::Transaction t;
@@ -653,23 +652,6 @@ bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string>
}
void BootAnimation::findBootAnimationFile() {
- // If the device has encryption turned on or is in process
- // of being encrypted we show the encrypted boot animation.
- char decrypt[PROPERTY_VALUE_MAX];
- property_get("vold.decrypt", decrypt, "");
-
- bool encryptedAnimation = atoi(decrypt) != 0 ||
- !strcmp("trigger_restart_min_framework", decrypt);
-
- if (!mShuttingDown && encryptedAnimation) {
- static const std::vector<std::string> encryptedBootFiles = {
- PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,
- };
- if (findBootAnimationFileInternal(encryptedBootFiles)) {
- return;
- }
- }
-
const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
static const std::vector<std::string> bootFiles = {
APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 64814c8a25e2..988685e23443 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -4,7 +4,6 @@
The system selects a boot animation zipfile from the following locations, in order:
- /system/media/bootanimation-encrypted.zip (if getprop("vold.decrypt") = '1')
/system/media/bootanimation.zip
/oem/media/bootanimation.zip
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 6ef6845c75f2..18ec5a407b24 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,6 +23,7 @@ package {
cc_defaults {
name: "idmap2_defaults",
+ cpp_std: "gnu++2b",
tidy: true,
tidy_checks: [
"modernize-*",
@@ -31,6 +32,7 @@ cc_defaults {
"android-*",
"misc-*",
"readability-*",
+ "-readability-identifier-length",
],
tidy_checks_as_errors: [
"modernize-*",
@@ -54,7 +56,6 @@ cc_defaults {
"-readability-convert-member-functions-to-static",
"-readability-duplicate-include",
"-readability-else-after-return",
- "-readability-identifier-length",
"-readability-named-parameter",
"-readability-redundant-access-specifiers",
"-readability-uppercase-literal-suffix",
@@ -115,6 +116,7 @@ cc_library {
"libidmap2/proto/*.proto",
],
host_supported: true,
+ tidy: false,
proto: {
type: "lite",
export_proto_headers: true,
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
index f2f8854cec3a..f9c4fa3c798b 100644
--- a/cmds/idmap2/tests/ResultTests.cpp
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -259,7 +259,8 @@ TEST(ResultTests, CascadeError) {
}
struct NoCopyContainer {
- uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
+ uint32_t value = 0; // NOLINT(misc-non-private-member-variables-in-classes)
+ NoCopyContainer() = default;
NoCopyContainer(const NoCopyContainer&) = delete;
NoCopyContainer& operator=(const NoCopyContainer&) = delete;
};
@@ -268,7 +269,7 @@ Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
if (!succeed) {
return Error("foo");
}
- std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
+ std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{});
p->value = 42U;
return std::move(p);
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index d464e266ac36..13c7946a033f 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -54,7 +54,7 @@ public final class Telecom extends BaseCommand {
(new Telecom()).run(args);
}
-
+ private static final String CALLING_PACKAGE = Telecom.class.getPackageName();
private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled";
private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled";
private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account";
@@ -297,7 +297,7 @@ public final class Telecom extends BaseCommand {
final String label = nextArgRequired();
PhoneAccount account = PhoneAccount.builder(handle, label)
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER).build();
- mTelecomService.registerPhoneAccount(account);
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
System.out.println("Success - " + handle + " registered.");
}
@@ -327,7 +327,7 @@ public final class Telecom extends BaseCommand {
.addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
.addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
.build();
- mTelecomService.registerPhoneAccount(account);
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
System.out.println("Success - " + handle + " registered.");
}
@@ -369,7 +369,7 @@ public final class Telecom extends BaseCommand {
private void runUnregisterPhoneAccount() throws RemoteException {
final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
- mTelecomService.unregisterPhoneAccount(handle);
+ mTelecomService.unregisterPhoneAccount(handle, CALLING_PACKAGE);
System.out.println("Success - " + handle + " unregistered.");
}
@@ -406,11 +406,11 @@ public final class Telecom extends BaseCommand {
}
private void runGetDefaultDialer() throws RemoteException {
- System.out.println(mTelecomService.getDefaultDialerPackage());
+ System.out.println(mTelecomService.getDefaultDialerPackage(CALLING_PACKAGE));
}
private void runGetSystemDialer() throws RemoteException {
- System.out.println(mTelecomService.getSystemDialerPackage());
+ System.out.println(mTelecomService.getSystemDialerPackage(CALLING_PACKAGE));
}
private void runWaitOnHandler() throws RemoteException {
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
index 06fa2aac2c7e..3f4163dc54ec 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -99,6 +99,7 @@ JNIEnv* DeviceCallback::getJNIEnv() {
std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid,
int32_t pid, uint16_t bus, uint32_t ffEffectsMax,
+ const char* port,
std::unique_ptr<DeviceCallback> callback) {
android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
if (!fd.ok()) {
@@ -131,6 +132,9 @@ std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, i
return nullptr;
}
+ // set the physical port.
+ ::ioctl(fd, UI_SET_PHYS, port);
+
if (::ioctl(fd, UI_DEV_CREATE) != 0) {
ALOGE("Unable to create uinput device: %s.", strerror(errno));
return nullptr;
@@ -240,17 +244,19 @@ std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
}
static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
- jint pid, jint bus, jint ffEffectsMax, jobject callback) {
+ jint pid, jint bus, jint ffEffectsMax, jstring rawPort,
+ jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
}
+ ScopedUtfChars port(env, rawPort);
std::unique_ptr<uinput::DeviceCallback> cb =
std::make_unique<uinput::DeviceCallback>(env, callback);
std::unique_ptr<uinput::UinputDevice> d =
- uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax,
+ uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax, port.c_str(),
std::move(cb));
return reinterpret_cast<jlong>(d.release());
}
@@ -303,7 +309,7 @@ static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCo
static JNINativeMethod sMethods[] = {
{"nativeOpenUinputDevice",
- "(Ljava/lang/String;IIIII"
+ "(Ljava/lang/String;IIIIILjava/lang/String;"
"Lcom/android/commands/uinput/Device$DeviceCallback;)J",
reinterpret_cast<void*>(openUinputDevice)},
{"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)},
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h
index 5a9a06cfb32e..6da3d7968ed0 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.h
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h
@@ -48,6 +48,7 @@ class UinputDevice {
public:
static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid,
int32_t pid, uint16_t bus, uint32_t ff_effects_max,
+ const char* port,
std::unique_ptr<DeviceCallback> callback);
virtual ~UinputDevice();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index 62bee7b964bd..732b33d60c15 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -61,7 +61,7 @@ public class Device {
}
private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid,
- int bus, int ffEffectsMax, DeviceCallback callback);
+ int bus, int ffEffectsMax, String port, DeviceCallback callback);
private static native void nativeCloseUinputDevice(long ptr);
private static native void nativeInjectEvent(long ptr, int type, int code, int value);
private static native void nativeConfigure(int handle, int code, int[] configs);
@@ -69,7 +69,7 @@ public class Device {
public Device(int id, String name, int vid, int pid, int bus,
SparseArray<int[]> configuration, int ffEffectsMax,
- SparseArray<InputAbsInfo> absInfo) {
+ SparseArray<InputAbsInfo> absInfo, String port) {
mId = id;
mThread = new HandlerThread("UinputDeviceHandler");
mThread.start();
@@ -88,6 +88,11 @@ public class Device {
} else {
args.arg1 = id + ":" + vid + ":" + pid;
}
+ if (port != null) {
+ args.arg2 = port;
+ } else {
+ args.arg2 = "uinput:" + id + ":" + vid + ":" + pid;
+ }
mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
mTimeToSend = SystemClock.uptimeMillis();
@@ -142,7 +147,7 @@ public class Device {
case MSG_OPEN_UINPUT_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
mPtr = nativeOpenUinputDevice((String) args.arg1, args.argi1, args.argi2,
- args.argi3, args.argi4, args.argi5,
+ args.argi3, args.argi4, args.argi5, (String) args.arg2,
new DeviceCallback());
break;
case MSG_INJECT_EVENT:
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index c4ba05054eda..9add310effaa 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -64,6 +64,7 @@ public class Event {
private SparseArray<int[]> mConfiguration;
private int mDuration;
private int mFfEffectsMax = 0;
+ private String mInputport;
private SparseArray<InputAbsInfo> mAbsInfo;
public int getId() {
@@ -110,6 +111,10 @@ public class Event {
return mAbsInfo;
}
+ public String getPort() {
+ return mInputport;
+ }
+
/**
* Convert an event to String.
*/
@@ -124,6 +129,7 @@ public class Event {
+ ", configuration=" + mConfiguration
+ ", duration=" + mDuration
+ ", ff_effects_max=" + mFfEffectsMax
+ + ", port=" + mInputport
+ "}";
}
@@ -178,6 +184,10 @@ public class Event {
mEvent.mAbsInfo = absInfo;
}
+ public void setInputport(String port) {
+ mEvent.mInputport = port;
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
@@ -262,6 +272,9 @@ public class Event {
case "duration":
eb.setDuration(readInt());
break;
+ case "port":
+ eb.setInputport(mReader.nextString());
+ break;
default:
mReader.skipValue();
}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index f7601a2f7c07..740578e878ac 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -123,7 +123,7 @@ public class Uinput {
}
int id = e.getId();
Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
- e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo());
+ e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo(), e.getPort());
mDevices.append(id, d);
}
diff --git a/core/api/current.txt b/core/api/current.txt
index c8a43db2f9c2..31b0f057d4ea 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -786,6 +786,10 @@ package android {
field public static final int hand_secondTintMode = 16844349; // 0x101063d
field public static final int handle = 16843354; // 0x101025a
field public static final int handleProfiling = 16842786; // 0x1010022
+ field public static final int handwritingBoundsOffsetBottom;
+ field public static final int handwritingBoundsOffsetLeft;
+ field public static final int handwritingBoundsOffsetRight;
+ field public static final int handwritingBoundsOffsetTop;
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
field public static final int hardwareAccelerated = 16843475; // 0x10102d3
field public static final int hasCode = 16842764; // 0x101000c
@@ -7669,7 +7673,7 @@ package android.app.admin {
field public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
field public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
- field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
+ field @Deprecated public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
field public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5; // 0x5
@@ -8996,6 +9000,7 @@ package android.companion {
public final class CompanionDeviceManager {
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback);
+ method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
method @Deprecated public void disassociate(@NonNull String);
method public void disassociate(int);
method @Deprecated @NonNull public java.util.List<java.lang.String> getAssociations();
@@ -9003,6 +9008,7 @@ package android.companion {
method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
method public void requestNotificationAccess(android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
+ method public void startSystemDataTransfer(int) throws android.companion.DeviceNotAssociatedException;
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
field public static final String EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION";
field @Deprecated public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
@@ -9018,11 +9024,13 @@ package android.companion {
public abstract class CompanionDeviceService extends android.app.Service {
ctor public CompanionDeviceService();
+ method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public final void dispatchMessageToSystem(int, int, @NonNull byte[]) throws android.companion.DeviceNotAssociatedException;
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method @Deprecated @MainThread public void onDeviceAppeared(@NonNull String);
method @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull String);
method @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
+ method public void onMessageDispatchedFromSystem(int, int, @NonNull byte[]);
field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
}
@@ -10878,7 +10886,7 @@ package android.content {
}
public static interface SharedPreferences.OnSharedPreferenceChangeListener {
- method public void onSharedPreferenceChanged(android.content.SharedPreferences, String);
+ method public void onSharedPreferenceChanged(android.content.SharedPreferences, @Nullable String);
}
public class SyncAdapterType implements android.os.Parcelable {
@@ -18526,7 +18534,7 @@ package android.hardware.fingerprint {
package android.hardware.input {
public final class InputManager {
- method public android.view.InputDevice getInputDevice(int);
+ method @Nullable public android.view.InputDevice getInputDevice(int);
method public int[] getInputDeviceIds();
method @FloatRange(from=0, to=1) public float getMaximumObscuringOpacityForTouch();
method public void registerInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener, android.os.Handler);
@@ -19107,41 +19115,41 @@ package android.location {
field @NonNull public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
}
- public class Criteria implements android.os.Parcelable {
- ctor public Criteria();
- ctor public Criteria(android.location.Criteria);
- method public int describeContents();
- method public int getAccuracy();
- method public int getBearingAccuracy();
- method public int getHorizontalAccuracy();
- method public int getPowerRequirement();
- method public int getSpeedAccuracy();
- method public int getVerticalAccuracy();
- method public boolean isAltitudeRequired();
- method public boolean isBearingRequired();
- method public boolean isCostAllowed();
- method public boolean isSpeedRequired();
- method public void setAccuracy(int);
- method public void setAltitudeRequired(boolean);
- method public void setBearingAccuracy(int);
- method public void setBearingRequired(boolean);
- method public void setCostAllowed(boolean);
- method public void setHorizontalAccuracy(int);
- method public void setPowerRequirement(int);
- method public void setSpeedAccuracy(int);
- method public void setSpeedRequired(boolean);
- method public void setVerticalAccuracy(int);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int ACCURACY_COARSE = 2; // 0x2
- field public static final int ACCURACY_FINE = 1; // 0x1
- field public static final int ACCURACY_HIGH = 3; // 0x3
- field public static final int ACCURACY_LOW = 1; // 0x1
- field public static final int ACCURACY_MEDIUM = 2; // 0x2
- field @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
- field public static final int NO_REQUIREMENT = 0; // 0x0
- field public static final int POWER_HIGH = 3; // 0x3
- field public static final int POWER_LOW = 1; // 0x1
- field public static final int POWER_MEDIUM = 2; // 0x2
+ @Deprecated public class Criteria implements android.os.Parcelable {
+ ctor @Deprecated public Criteria();
+ ctor @Deprecated public Criteria(android.location.Criteria);
+ method @Deprecated public int describeContents();
+ method @Deprecated public int getAccuracy();
+ method @Deprecated public int getBearingAccuracy();
+ method @Deprecated public int getHorizontalAccuracy();
+ method @Deprecated public int getPowerRequirement();
+ method @Deprecated public int getSpeedAccuracy();
+ method @Deprecated public int getVerticalAccuracy();
+ method @Deprecated public boolean isAltitudeRequired();
+ method @Deprecated public boolean isBearingRequired();
+ method @Deprecated public boolean isCostAllowed();
+ method @Deprecated public boolean isSpeedRequired();
+ method @Deprecated public void setAccuracy(int);
+ method @Deprecated public void setAltitudeRequired(boolean);
+ method @Deprecated public void setBearingAccuracy(int);
+ method @Deprecated public void setBearingRequired(boolean);
+ method @Deprecated public void setCostAllowed(boolean);
+ method @Deprecated public void setHorizontalAccuracy(int);
+ method @Deprecated public void setPowerRequirement(int);
+ method @Deprecated public void setSpeedAccuracy(int);
+ method @Deprecated public void setSpeedRequired(boolean);
+ method @Deprecated public void setVerticalAccuracy(int);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public static final int ACCURACY_COARSE = 2; // 0x2
+ field @Deprecated public static final int ACCURACY_FINE = 1; // 0x1
+ field @Deprecated public static final int ACCURACY_HIGH = 3; // 0x3
+ field @Deprecated public static final int ACCURACY_LOW = 1; // 0x1
+ field @Deprecated public static final int ACCURACY_MEDIUM = 2; // 0x2
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
+ field @Deprecated public static final int NO_REQUIREMENT = 0; // 0x0
+ field @Deprecated public static final int POWER_HIGH = 3; // 0x3
+ field @Deprecated public static final int POWER_LOW = 1; // 0x1
+ field @Deprecated public static final int POWER_MEDIUM = 2; // 0x2
}
public final class Geocoder {
@@ -19525,6 +19533,8 @@ package android.location {
method @Nullable public android.os.Bundle getExtras();
method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
+ method @FloatRange(from=0.0) public float getMslAltitudeAccuracyMeters();
+ method @FloatRange public double getMslAltitudeMeters();
method @Nullable public String getProvider();
method @FloatRange(from=0.0) public float getSpeed();
method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
@@ -19535,6 +19545,8 @@ package android.location {
method public boolean hasBearing();
method public boolean hasBearingAccuracy();
method public boolean hasElapsedRealtimeUncertaintyNanos();
+ method public boolean hasMslAltitude();
+ method public boolean hasMslAltitudeAccuracy();
method public boolean hasSpeed();
method public boolean hasSpeedAccuracy();
method public boolean hasVerticalAccuracy();
@@ -19546,6 +19558,8 @@ package android.location {
method public void removeBearing();
method public void removeBearingAccuracy();
method public void removeElapsedRealtimeUncertaintyNanos();
+ method public void removeMslAltitude();
+ method public void removeMslAltitudeAccuracy();
method public void removeSpeed();
method public void removeSpeedAccuracy();
method public void removeVerticalAccuracy();
@@ -19561,6 +19575,8 @@ package android.location {
method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
method public void setMock(boolean);
+ method public void setMslAltitudeAccuracyMeters(@FloatRange(from=0.0) float);
+ method public void setMslAltitudeMeters(@FloatRange double);
method public void setProvider(@Nullable String);
method public void setSpeed(@FloatRange(from=0.0) float);
method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
@@ -19596,7 +19612,7 @@ package android.location {
method @Deprecated public void clearTestProviderLocation(@NonNull String);
method @Deprecated public void clearTestProviderStatus(@NonNull String);
method @NonNull public java.util.List<java.lang.String> getAllProviders();
- method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
+ method @Deprecated @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public java.util.List<android.location.GnssAntennaInfo> getGnssAntennaInfos();
@@ -19608,7 +19624,7 @@ package android.location {
method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
method @Nullable public android.location.provider.ProviderProperties getProviderProperties(@NonNull String);
method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
- method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
method public boolean hasProvider(@NonNull String);
method public boolean isLocationEnabled();
method public boolean isProviderEnabled(@NonNull String);
@@ -20081,14 +20097,14 @@ package android.media {
method @Deprecated public int getVibrateSetting(int);
method @Deprecated public boolean isBluetoothA2dpOn();
method public boolean isBluetoothScoAvailableOffCall();
- method public boolean isBluetoothScoOn();
+ method @Deprecated public boolean isBluetoothScoOn();
method public boolean isCallScreeningModeSupported();
method public static boolean isHapticPlaybackSupported();
method public boolean isMicrophoneMute();
method public boolean isMusicActive();
method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
method public boolean isRampingRingerEnabled();
- method public boolean isSpeakerphoneOn();
+ method @Deprecated public boolean isSpeakerphoneOn();
method public boolean isStreamMute(int);
method public boolean isSurroundFormatEnabled(int);
method public boolean isVolumeFixed();
@@ -20117,7 +20133,7 @@ package android.media {
method public void setParameters(String);
method public void setRingerMode(int);
method @Deprecated public void setRouting(int, int, int);
- method public void setSpeakerphoneOn(boolean);
+ method @Deprecated public void setSpeakerphoneOn(boolean);
method @Deprecated public void setStreamMute(int, boolean);
method @Deprecated public void setStreamSolo(int, boolean);
method public void setStreamVolume(int, int, int);
@@ -20125,8 +20141,8 @@ package android.media {
method @Deprecated public void setVibrateSetting(int, int);
method @Deprecated public void setWiredHeadsetOn(boolean);
method @Deprecated public boolean shouldVibrate(int);
- method public void startBluetoothSco();
- method public void stopBluetoothSco();
+ method @Deprecated public void startBluetoothSco();
+ method @Deprecated public void stopBluetoothSco();
method public void unloadSoundEffects();
method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
method public void unregisterAudioPlaybackCallback(@NonNull android.media.AudioManager.AudioPlaybackCallback);
@@ -22297,6 +22313,7 @@ package android.media {
field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
field public static final String KEY_WIDTH = "width";
+ field public static final String LOG_SESSION_ID = "log-session-id";
field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final String MIMETYPE_AUDIO_AAC_ELD = "audio/mp4a.40.39";
field public static final String MIMETYPE_AUDIO_AAC_HE_V1 = "audio/mp4a.40.05";
@@ -24307,7 +24324,7 @@ package android.media.audiofx {
method public int getWaveForm(byte[]) throws java.lang.IllegalStateException;
method public void release();
method public int setCaptureSize(int) throws java.lang.IllegalStateException;
- method public int setDataCaptureListener(android.media.audiofx.Visualizer.OnDataCaptureListener, int, boolean, boolean);
+ method public int setDataCaptureListener(@Nullable android.media.audiofx.Visualizer.OnDataCaptureListener, int, boolean, boolean);
method public int setEnabled(boolean) throws java.lang.IllegalStateException;
method public int setMeasurementMode(int) throws java.lang.IllegalStateException;
method public int setScalingMode(int) throws java.lang.IllegalStateException;
@@ -30978,6 +30995,7 @@ package android.os {
field public static final int S = 31; // 0x1f
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 33; // 0x21
+ field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -31432,6 +31450,7 @@ package android.os {
public static interface IBinder.DeathRecipient {
method public void binderDied();
+ method public default void binderDied(@NonNull android.os.IBinder);
}
public interface IInterface {
@@ -32341,6 +32360,9 @@ package android.os {
method public static android.os.VibrationEffect createWaveform(long[], int[], int);
method public int describeContents();
method @NonNull public static android.os.VibrationEffect.Composition startComposition();
+ method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform();
+ method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter);
+ method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
field public static final int EFFECT_CLICK = 0; // 0x0
@@ -32350,10 +32372,13 @@ package android.os {
}
public static final class VibrationEffect.Composition {
+ method @NonNull public android.os.VibrationEffect.Composition addEffect(@NonNull android.os.VibrationEffect);
+ method @NonNull public android.os.VibrationEffect.Composition addOffDuration(@NonNull java.time.Duration);
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int);
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float);
method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
method @NonNull public android.os.VibrationEffect compose();
+ method @NonNull public android.os.VibrationEffect.Composition repeatEffectIndefinitely(@NonNull android.os.VibrationEffect);
field public static final int PRIMITIVE_CLICK = 1; // 0x1
field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8
field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
@@ -32364,15 +32389,34 @@ package android.os {
field public static final int PRIMITIVE_TICK = 7; // 0x7
}
+ public static final class VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException extends java.lang.IllegalStateException {
+ }
+
+ public static class VibrationEffect.VibrationParameter {
+ method @NonNull public static android.os.VibrationEffect.VibrationParameter targetAmplitude(@FloatRange(from=0, to=1) float);
+ method @NonNull public static android.os.VibrationEffect.VibrationParameter targetFrequency(@FloatRange(from=1) float);
+ }
+
+ public static final class VibrationEffect.WaveformBuilder {
+ method @NonNull public android.os.VibrationEffect.WaveformBuilder addSustain(@NonNull java.time.Duration);
+ method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter);
+ method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
+ method @NonNull public android.os.VibrationEffect build();
+ }
+
public abstract class Vibrator {
method public final int areAllEffectsSupported(@NonNull int...);
method public final boolean areAllPrimitivesSupported(@NonNull int...);
method @NonNull public int[] areEffectsSupported(@NonNull int...);
method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
+ method @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
method public int getId();
method @NonNull public int[] getPrimitiveDurations(@NonNull int...);
+ method public float getQFactor();
+ method public float getResonantFrequency();
method public abstract boolean hasAmplitudeControl();
+ method public boolean hasFrequencyControl();
method public abstract boolean hasVibrator();
method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long);
method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long, android.media.AudioAttributes);
@@ -32700,6 +32744,17 @@ package android.os.strictmode {
}
+package android.os.vibrator {
+
+ public final class VibratorFrequencyProfile {
+ method public float getMaxAmplitudeMeasurementInterval();
+ method @FloatRange(from=0, to=1) @NonNull public float[] getMaxAmplitudeMeasurements();
+ method public float getMaxFrequency();
+ method public float getMinFrequency();
+ }
+
+}
+
package android.preference {
@Deprecated public class CheckBoxPreference extends android.preference.TwoStatePreference {
@@ -39029,6 +39084,7 @@ package android.service.notification {
field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+ field public static final int REASON_LOCKDOWN = 23; // 0x17
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
@@ -48126,7 +48182,7 @@ package android.view {
method @NonNull public android.hardware.BatteryState getBatteryState();
method public int getControllerNumber();
method public String getDescriptor();
- method public static android.view.InputDevice getDevice(int);
+ method @Nullable public static android.view.InputDevice getDevice(int);
method public static int[] getDeviceIds();
method public int getId();
method public android.view.KeyCharacterMap getKeyCharacterMap();
@@ -49672,6 +49728,10 @@ package android.view {
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
+ method public float getHandwritingBoundsOffsetBottom();
+ method public float getHandwritingBoundsOffsetLeft();
+ method public float getHandwritingBoundsOffsetRight();
+ method public float getHandwritingBoundsOffsetTop();
method public final boolean getHasOverlappingRendering();
method public final int getHeight();
method public void getHitRect(android.graphics.Rect);
@@ -50035,6 +50095,7 @@ package android.view {
method public void setForegroundTintBlendMode(@Nullable android.graphics.BlendMode);
method public void setForegroundTintList(@Nullable android.content.res.ColorStateList);
method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
+ method public void setHandwritingBoundsOffsets(float, float, float, float);
method public void setHapticFeedbackEnabled(boolean);
method public void setHasTransientState(boolean);
method public void setHorizontalFadingEdgeEnabled(boolean);
@@ -50478,6 +50539,7 @@ package android.view {
method public int getScaledDoubleTapSlop();
method public int getScaledEdgeSlop();
method public int getScaledFadingEdgeLength();
+ method public int getScaledHandwritingSlop();
method public float getScaledHorizontalScrollFactor();
method public int getScaledHoverSlop();
method public int getScaledMaximumDrawingCacheSize();
@@ -51431,6 +51493,7 @@ package android.view {
ctor public WindowManager.LayoutParams(int, int, int, int, int);
ctor public WindowManager.LayoutParams(int, int, int, int, int, int, int);
ctor public WindowManager.LayoutParams(android.os.Parcel);
+ method public boolean areWallpaperTouchEventsEnabled();
method public final int copyFrom(android.view.WindowManager.LayoutParams);
method public String debug(String);
method public int describeContents();
@@ -51447,6 +51510,7 @@ package android.view {
method public void setFitInsetsSides(int);
method public void setFitInsetsTypes(int);
method public final void setTitle(CharSequence);
+ method public void setWallpaperTouchEventsEnabled(boolean);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALPHA_CHANGED = 128; // 0x80
field public static final int ANIMATION_CHANGED = 16; // 0x10
@@ -52505,6 +52569,7 @@ package android.view.autofill {
public final class AutofillManager {
method public void cancel();
+ method public void clearAutofillRequestCallback();
method public void commit();
method public void disableAutofillServices();
method @Nullable public android.content.ComponentName getAutofillServiceComponentName();
@@ -52530,6 +52595,7 @@ package android.view.autofill {
method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
method public void requestAutofill(@NonNull android.view.View);
method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
+ method public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
method public void setUserData(@Nullable android.service.autofill.UserData);
method public boolean showAutofillDialog(@NonNull android.view.View);
method public boolean showAutofillDialog(@NonNull android.view.View, int);
@@ -52550,6 +52616,10 @@ package android.view.autofill {
field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
+ public interface AutofillRequestCallback {
+ method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
+ }
+
public final class AutofillValue implements android.os.Parcelable {
method public int describeContents();
method public static android.view.autofill.AutofillValue forDate(long);
@@ -52937,10 +53007,12 @@ package android.view.inputmethod {
ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
+ method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
+ method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
}
@@ -53117,6 +53189,7 @@ package android.view.inputmethod {
method public boolean isActive();
method public boolean isFullscreenMode();
method public boolean isInputMethodSuppressingSpellChecker();
+ method public boolean isStylusHandwritingAvailable();
method @Deprecated public boolean isWatchingCursor(android.view.View);
method public void restartInput(android.view.View);
method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b9522163b5d0..610cb9450c77 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -2,6 +2,7 @@
package android {
public static final class Manifest.permission {
+ field public static final String BLUETOOTH_STACK = "android.permission.BLUETOOTH_STACK";
field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
@@ -156,12 +157,12 @@ package android.media {
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean);
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpSamplingRate(int);
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpVolume(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setA2dpSuspended(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpSamplingRate(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpVolume(int);
method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
@@ -357,6 +358,7 @@ package android.os {
public final class ServiceManager {
method public static boolean isDeclared(@NonNull String);
method @Nullable public static android.os.IBinder waitForDeclaredService(@NonNull String);
+ method @Nullable public static android.os.IBinder waitForService(@NonNull String);
}
public class StatsServiceManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ec4ad8b704c3..e224a01e367e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -199,6 +199,7 @@ package android {
field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
field public static final String MARK_DEVICE_ORGANIZATION_OWNED = "android.permission.MARK_DEVICE_ORGANIZATION_OWNED";
+ field public static final String MEDIA_RESOURCE_OVERRIDE_PID = "android.permission.MEDIA_RESOURCE_OVERRIDE_PID";
field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
@@ -1050,7 +1051,7 @@ package android.app {
public class WallpaperManager {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void clearWallpaper(int, int);
- method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public float getWallpaperDimAmount();
+ method @FloatRange(from=0.0f, to=1.0f) @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public float getWallpaperDimAmount();
method public void setDisplayOffset(android.os.IBinder, int, int);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public void setWallpaperDimAmount(@FloatRange(from=0.0f, to=1.0f) float);
@@ -2743,6 +2744,7 @@ package android.apphibernation {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public java.util.Map<java.lang.String,android.apphibernation.HibernationStats> getHibernationStatsForUser();
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingForUser(@NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingGlobally(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isOatArtifactDeletionEnabled();
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingForUser(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingGlobally(@NonNull String, boolean);
}
@@ -5875,7 +5877,7 @@ package android.location {
}
public class LocationManager {
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
+ method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
@@ -6334,7 +6336,7 @@ package android.media {
}
public final class MediaCodec {
- method @NonNull @RequiresPermission("android.permission.MEDIA_RESOURCE_OVERRIDE_PID") public static android.media.MediaCodec createByCodecNameForClient(@NonNull String, int, int) throws java.io.IOException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_RESOURCE_OVERRIDE_PID) public static android.media.MediaCodec createByCodecNameForClient(@NonNull String, int, int) throws java.io.IOException;
}
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
@@ -9779,6 +9781,7 @@ package android.os {
method @NonNull public static String formatUid(int);
method public static int getAppId(int);
method public int getIdentifier();
+ method public static int getSharedAppGid(int);
method public int getUid(int);
method @Deprecated public boolean isOwner();
method public boolean isSystem();
@@ -9816,7 +9819,7 @@ package android.os {
method public boolean isCredentialSharableWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
+ method public boolean isMediaSharedWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
method public static boolean isRemoveResultSuccessful(int);
method public boolean isRestrictedProfile();
@@ -11873,19 +11876,20 @@ package android.service.trust {
package android.service.voice {
public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
- method @Nullable public android.content.Intent createEnrollIntent();
- method @Nullable public android.content.Intent createReEnrollIntent();
- method @Nullable public android.content.Intent createUnEnrollIntent();
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int getParameter(int);
+ method @Nullable public android.content.Intent createEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @Nullable public android.content.Intent createReEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @Nullable public android.content.Intent createUnEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int getParameter(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
method public int getSupportedAudioCapabilities();
- method public int getSupportedRecognitionModes();
- method @Nullable @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int setParameter(int, int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition();
- method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean stopRecognition();
- method public final void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory);
+ method public int getSupportedRecognitionModes() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @Nullable @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int setParameter(int, int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int, @NonNull byte[]) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean stopRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method public final void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
field public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 1; // 0x1
field public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2
field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0
@@ -11992,10 +11996,10 @@ package android.service.voice {
public interface HotwordDetector {
method public default void destroy();
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition();
- method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle);
- method public boolean stopRecognition();
- method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory);
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method public boolean stopRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
+ method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory) throws android.service.voice.HotwordDetector.IllegalDetectorStateException;
}
public static interface HotwordDetector.Callback {
@@ -12008,6 +12012,9 @@ package android.service.voice {
method public void onRejected(@NonNull android.service.voice.HotwordRejectedResult);
}
+ public static class HotwordDetector.IllegalDetectorStateException extends android.util.AndroidException {
+ }
+
public final class HotwordRejectedResult implements android.os.Parcelable {
method public int describeContents();
method public int getConfidenceLevel();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 48277fb3b488..2fff53791f52 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -96,6 +96,12 @@ package android.accessibilityservice {
package android.animation {
+ public abstract class Animator implements java.lang.Cloneable {
+ method public static long getBackgroundPauseDelay();
+ method public static void setAnimatorPausingEnabled(boolean);
+ method public static void setBackgroundPauseDelay(long);
+ }
+
public class ValueAnimator extends android.animation.Animator {
method @MainThread public static void setDurationScale(@FloatRange(from=0) float);
}
@@ -482,8 +488,6 @@ package android.app {
field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
field public static final int WINDOWING_MODE_MULTI_WINDOW = 6; // 0x6
field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
- field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
- field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
field public static final int WINDOWING_MODE_UNDEFINED = 0; // 0x0
}
@@ -1250,11 +1254,11 @@ package android.hardware.input {
}
public final class InputManager {
- method public int getBlockUntrustedTouchesMode(@NonNull android.content.Context);
+ method public void addUniqueIdAssociation(@NonNull String, @NonNull String);
method @Nullable public String getCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier);
method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptorsForInputDevice(@NonNull android.view.InputDevice);
method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setBlockUntrustedTouchesMode(@NonNull android.content.Context, int);
+ method public void removeUniqueIdAssociation(@NonNull String);
method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setMaximumObscuringOpacityForTouch(@FloatRange(from=0, to=1) float);
field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
@@ -1857,7 +1861,6 @@ package android.os {
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
- method public static boolean isGuestUserEphemeral();
method public static boolean isSplitSystemUser();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException;
}
@@ -1871,9 +1874,6 @@ package android.os {
method public static android.os.VibrationEffect get(int, boolean);
method @Nullable public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
method public abstract long getDuration();
- method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform();
- method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter);
- method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
field public static final int EFFECT_POP = 4; // 0x4
field public static final int EFFECT_STRENGTH_LIGHT = 0; // 0x0
field public static final int EFFECT_STRENGTH_MEDIUM = 1; // 0x1
@@ -1891,33 +1891,8 @@ package android.os {
field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Composed> CREATOR;
}
- public static final class VibrationEffect.Composition {
- method @NonNull public android.os.VibrationEffect.Composition addEffect(@NonNull android.os.VibrationEffect);
- method @NonNull public android.os.VibrationEffect.Composition addOffDuration(@NonNull java.time.Duration);
- method @NonNull public android.os.VibrationEffect.Composition repeatEffectIndefinitely(@NonNull android.os.VibrationEffect);
- }
-
- public static final class VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException extends java.lang.IllegalStateException {
- }
-
- public static class VibrationEffect.VibrationParameter {
- method @NonNull public static android.os.VibrationEffect.VibrationParameter targetAmplitude(@FloatRange(from=0, to=1) float);
- method @NonNull public static android.os.VibrationEffect.VibrationParameter targetFrequency(@FloatRange(from=1) float);
- }
-
- public static final class VibrationEffect.WaveformBuilder {
- method @NonNull public android.os.VibrationEffect.WaveformBuilder addSustain(@NonNull java.time.Duration);
- method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter);
- method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
- method @NonNull public android.os.VibrationEffect build();
- }
-
public abstract class Vibrator {
method public int getDefaultVibrationIntensity(int);
- method @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
- method public float getQFactor();
- method public float getResonantFrequency();
- method public boolean hasFrequencyControl();
field public static final int VIBRATION_INTENSITY_HIGH = 3; // 0x3
field public static final int VIBRATION_INTENSITY_LOW = 1; // 0x1
field public static final int VIBRATION_INTENSITY_MEDIUM = 2; // 0x2
@@ -2102,13 +2077,6 @@ package android.os.vibrator {
field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.VibrationEffectSegment> CREATOR;
}
- public final class VibratorFrequencyProfile {
- method public float getMaxAmplitudeMeasurementInterval();
- method @FloatRange(from=0, to=1) @NonNull public float[] getMaxAmplitudeMeasurements();
- method public float getMaxFrequency();
- method public float getMinFrequency();
- }
-
}
package android.permission {
@@ -2465,6 +2433,8 @@ package android.service.quicksettings {
package android.service.voice {
public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
+ method public void overrideAvailability(int);
+ method public void resetAvailability();
method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
}
@@ -2824,6 +2794,7 @@ package android.view {
method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut();
method @Nullable public android.view.Display.Mode getSystemPreferredDisplayMode();
method public int getType();
+ method @Nullable public String getUniqueId();
method @Nullable public android.view.Display.Mode getUserPreferredDisplayMode();
method public boolean hasAccess(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void setUserPreferredDisplayMode(@NonNull android.view.Display.Mode);
@@ -3396,7 +3367,7 @@ package android.window {
method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
- method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @Nullable android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams);
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index f7328457b379..46e2175384d0 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -15,14 +15,6 @@ filegroup {
"**/*.java",
"**/*.aidl",
],
- exclude_srcs: [
- // Remove election toolbar code from build time
- "android/service/selectiontoolbar/*.aidl",
- "android/service/selectiontoolbar/*.java",
- "android/view/selectiontoolbar/*.aidl",
- "android/view/selectiontoolbar/*.java",
- "com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java",
- ],
visibility: ["//frameworks/base"],
}
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index e6cdcc0ee742..0d6a07938e95 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,7 +31,6 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import java.util.Objects;
import java.util.Set;
/**
@@ -87,12 +86,6 @@ public class Account implements Parcelable {
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/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java
index 260323fe2d10..1cb2574ae8b7 100644
--- a/core/java/android/animation/AnimationHandler.java
+++ b/core/java/android/animation/AnimationHandler.java
@@ -18,6 +18,8 @@ package android.animation;
import android.os.SystemClock;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
import android.view.Choreographer;
import java.util.ArrayList;
@@ -35,10 +37,13 @@ import java.util.ArrayList;
* @hide
*/
public class AnimationHandler {
+
+ private static final String TAG = "AnimationHandler";
+ private static final boolean LOCAL_LOGV = false;
+
/**
* Internal per-thread collections used to avoid set collisions as animations start and end
* while being processed.
- * @hide
*/
private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime =
new ArrayMap<>();
@@ -48,6 +53,29 @@ public class AnimationHandler {
new ArrayList<>();
private AnimationFrameCallbackProvider mProvider;
+ // Static flag which allows the pausing behavior to be globally disabled/enabled.
+ private static boolean sAnimatorPausingEnabled = true;
+
+ /**
+ * This paused list is used to store animators forcibly paused when the activity
+ * went into the background (to avoid unnecessary background processing work).
+ * These animators should be resume()'d when the activity returns to the foreground.
+ */
+ private final ArrayList<Animator> mPausedAnimators = new ArrayList<>();
+
+ /**
+ * This structure is used to store the currently active objects (ViewRootImpls or
+ * WallpaperService.Engines) in the process. Each of these objects sends a request to
+ * AnimationHandler when it goes into the background (request to pause) or foreground
+ * (request to resume). Because all animators are managed by AnimationHandler on the same
+ * thread, it should only ever pause animators when *all* requestors are in the background.
+ * This list tracks the background/foreground state of all requestors and only ever
+ * pauses animators when all items are in the background (false). To simplify, we only ever
+ * store visible (foreground) requestors; if the set size reaches zero, there are no
+ * objects in the foreground and it is time to pause animators.
+ */
+ private final ArraySet<Object> mAnimatorRequestors = new ArraySet<>();
+
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
@@ -69,6 +97,109 @@ public class AnimationHandler {
}
/**
+ * Disable the default behavior of pausing infinite animators when
+ * apps go into the background.
+ *
+ * @param enable Enable (default behavior) or disable background pausing behavior.
+ */
+ public static void setAnimatorPausingEnabled(boolean enable) {
+ sAnimatorPausingEnabled = enable;
+ }
+
+ /**
+ * This is called when a window goes away. We should remove
+ * it from the requestors list to ensure that we are counting requests correctly and not
+ * tracking obsolete+enabled requestors.
+ */
+ public static void removeRequestor(Object requestor) {
+ getInstance().removeRequestorImpl(requestor);
+ }
+
+ private void removeRequestorImpl(Object requestor) {
+ // Also request disablement, in case that requestor was the sole object keeping
+ // animators un-paused
+ requestAnimatorsEnabled(false, requestor);
+ mAnimatorRequestors.remove(requestor);
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "removeRequestorImpl for " + requestor);
+ for (int i = 0; i < mAnimatorRequestors.size(); ++i) {
+ Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * This method is called from ViewRootImpl or WallpaperService when either a window is no
+ * longer visible (enable == false) or when a window becomes visible (enable == true).
+ * If animators are not properly disabled when activities are backgrounded, it can lead to
+ * unnecessary processing, particularly for infinite animators, as the system will continue
+ * to pulse timing events even though the results are not visible. As a workaround, we
+ * pause all un-paused infinite animators, and resume them when any window in the process
+ * becomes visible.
+ */
+ public static void requestAnimatorsEnabled(boolean enable, Object requestor) {
+ getInstance().requestAnimatorsEnabledImpl(enable, requestor);
+ }
+
+ private void requestAnimatorsEnabledImpl(boolean enable, Object requestor) {
+ boolean wasEmpty = mAnimatorRequestors.isEmpty();
+ if (enable) {
+ mAnimatorRequestors.add(requestor);
+ } else {
+ mAnimatorRequestors.remove(requestor);
+ }
+ if (!sAnimatorPausingEnabled) {
+ // Resume any animators that have been paused in the meantime, otherwise noop
+ // Leave logic above so that if pausing gets re-enabled, the state of the requestors
+ // list is valid
+ resumeAnimators();
+ return;
+ }
+ boolean isEmpty = mAnimatorRequestors.isEmpty();
+ if (wasEmpty != isEmpty) {
+ // only paused/resume animators if there was a visibility change
+ if (!isEmpty) {
+ // If any requestors are enabled, resume currently paused animators
+ resumeAnimators();
+ } else {
+ // Wait before pausing to avoid thrashing animator state for temporary backgrounding
+ Choreographer.getInstance().postFrameCallbackDelayed(mPauser,
+ Animator.getBackgroundPauseDelay());
+ }
+ }
+ if (LOCAL_LOGV) {
+ Log.v(TAG, enable ? "enable" : "disable" + " animators for " + requestor);
+ for (int i = 0; i < mAnimatorRequestors.size(); ++i) {
+ Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i));
+ }
+ }
+ }
+
+ private void resumeAnimators() {
+ Choreographer.getInstance().removeFrameCallback(mPauser);
+ for (int i = mPausedAnimators.size() - 1; i >= 0; --i) {
+ mPausedAnimators.get(i).resume();
+ }
+ mPausedAnimators.clear();
+ }
+
+ private Choreographer.FrameCallback mPauser = frameTimeNanos -> {
+ if (mAnimatorRequestors.size() > 0) {
+ // something enabled animators since this callback was scheduled - bail
+ return;
+ }
+ for (int i = 0; i < mAnimationCallbacks.size(); ++i) {
+ Animator animator = ((Animator) mAnimationCallbacks.get(i));
+ if (animator != null
+ && animator.getTotalDuration() == Animator.DURATION_INFINITE
+ && !animator.isPaused()) {
+ mPausedAnimators.add(animator);
+ animator.pause();
+ }
+ }
+ };
+
+ /**
* By default, the Choreographer is used to provide timing for frame callbacks. A custom
* provider can be used here to provide different timing pulse.
*/
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a8ff36aae098..f69decb087f3 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -18,6 +18,7 @@ package android.animation;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ConstantState;
@@ -64,6 +65,48 @@ public abstract class Animator implements Cloneable {
private AnimatorConstantState mConstantState;
/**
+ * backing field for backgroundPauseDelay property. This could be simply a hardcoded
+ * value in AnimationHandler, but it is useful to be able to change the value in tests.
+ */
+ private static long sBackgroundPauseDelay = 10000;
+
+ /**
+ * Sets the duration for delaying pausing animators when apps go into the background.
+ * Used by AnimationHandler when requested to pause animators.
+ *
+ * @hide
+ */
+ @TestApi
+ public static void setBackgroundPauseDelay(long value) {
+ sBackgroundPauseDelay = value;
+ }
+
+ /**
+ * Gets the duration for delaying pausing animators when apps go into the background.
+ * Used by AnimationHandler when requested to pause animators.
+ *
+ * @hide
+ */
+ @TestApi
+ public static long getBackgroundPauseDelay() {
+ return sBackgroundPauseDelay;
+ }
+
+ /**
+ * Sets the behavior of animator pausing when apps go into the background.
+ * This is exposed as a test API for verification, but is intended for use by internal/
+ * platform code, potentially for use by a system property that could disable it
+ * system wide.
+ *
+ * @param enable Enable (default behavior) or disable background pausing behavior.
+ * @hide
+ */
+ @TestApi
+ public static void setAnimatorPausingEnabled(boolean enable) {
+ AnimationHandler.setAnimatorPausingEnabled(enable);
+ }
+
+ /**
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
* running after that delay elapses. A non-delayed animation will have its initial
* value(s) set immediately, followed by calls to
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ae16e01b7788..7141259d7dce 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8260,6 +8260,11 @@ public class Activity extends ContextThemeWrapper
return mMainThread;
}
+ /** @hide */
+ public final ActivityInfo getActivityInfo() {
+ return mActivityInfo;
+ }
+
final void performCreate(Bundle icicle) {
performCreate(icicle, null);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5d1d225f4d2d..e25e374122cf 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2210,7 +2210,6 @@ public class ActivityManager {
pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
pw.print(" activityType="); pw.print(activityTypeToString(getActivityType()));
pw.print(" windowingMode="); pw.print(windowingModeToString(getWindowingMode()));
- pw.print(" supportsSplitScreenMultiWindow="); pw.print(supportsSplitScreenMultiWindow);
pw.print(" supportsMultiWindow=");
pw.println(supportsMultiWindow);
if (taskDescription != null) {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 2eebc01ccc04..d6441a2b629b 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -362,9 +363,8 @@ public class ActivityOptions extends ComponentOptions {
private static final String KEY_LAUNCH_INTO_PIP_PARAMS =
"android.activity.launchIntoPipParams";
- /** See {@link #setDismissKeyguardIfInsecure()}. */
- private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE =
- "android.activity.dismissKeyguardIfInsecure";
+ /** See {@link #setDismissKeyguard()}. */
+ private static final String KEY_DISMISS_KEYGUARD = "android.activity.dismissKeyguard";
private static final String KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE =
"android.activity.ignorePendingIntentCreatorForegroundState";
@@ -465,7 +465,7 @@ public class ActivityOptions extends ComponentOptions {
private boolean mLaunchedFromBubble;
private boolean mTransientLaunch;
private PictureInPictureParams mLaunchIntoPipParams;
- private boolean mDismissKeyguardIfInsecure;
+ private boolean mDismissKeyguard;
private boolean mIgnorePendingIntentCreatorForegroundState;
/**
@@ -1270,7 +1270,7 @@ public class ActivityOptions extends ComponentOptions {
mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS);
mIsEligibleForLegacyPermissionPrompt =
opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE);
- mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE);
+ mDismissKeyguard = opts.getBoolean(KEY_DISMISS_KEYGUARD);
mIgnorePendingIntentCreatorForegroundState = opts.getBoolean(
KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE);
}
@@ -1869,24 +1869,24 @@ public class ActivityOptions extends ComponentOptions {
}
/**
- * Sets whether the insecure keyguard should go away when this activity launches. In case the
- * keyguard is secure, this option will be ignored.
+ * Sets whether the keyguard should go away when this activity launches.
*
* @see Activity#setShowWhenLocked(boolean)
* @see android.R.attr#showWhenLocked
* @hide
*/
- public void setDismissKeyguardIfInsecure() {
- mDismissKeyguardIfInsecure = true;
+ @RequiresPermission(CONTROL_KEYGUARD)
+ public void setDismissKeyguard() {
+ mDismissKeyguard = true;
}
/**
- * @see #setDismissKeyguardIfInsecure()
+ * @see #setDismissKeyguard()
* @return whether the insecure keyguard should go away when the activity launches.
* @hide
*/
- public boolean getDismissKeyguardIfInsecure() {
- return mDismissKeyguardIfInsecure;
+ public boolean getDismissKeyguard() {
+ return mDismissKeyguard;
}
/**
@@ -2167,8 +2167,8 @@ public class ActivityOptions extends ComponentOptions {
b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE,
mIsEligibleForLegacyPermissionPrompt);
}
- if (mDismissKeyguardIfInsecure) {
- b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure);
+ if (mDismissKeyguard) {
+ b.putBoolean(KEY_DISMISS_KEYGUARD, mDismissKeyguard);
}
if (mIgnorePendingIntentCreatorForegroundState) {
b.putBoolean(KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1d1743f56ff7..86432ad63be8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -177,7 +177,6 @@ import android.view.DisplayAdjustments;
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import android.view.View;
-import android.view.ViewDebug;
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
@@ -208,7 +207,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
import com.android.server.am.MemInfoDumpProto;
@@ -1410,16 +1408,16 @@ public final class ActivityThread extends ClientTransactionHandler
ContextImpl.class,
Activity.class,
WebView.class,
- OpenSSLSocketImpl.class
+ View.class,
+ ViewRootImpl.class
};
long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
long appContextInstanceCount = instanceCounts[0];
long activityInstanceCount = instanceCounts[1];
long webviewInstanceCount = instanceCounts[2];
- long openSslSocketCount = instanceCounts[3];
+ long viewInstanceCount = instanceCounts[3];
+ long viewRootInstanceCount = instanceCounts[4];
- long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
int globalAssetCount = AssetManager.getGlobalAssetCount();
int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
@@ -1451,7 +1449,6 @@ public final class ActivityThread extends ClientTransactionHandler
pw.print(binderProxyObjectCount); pw.print(',');
pw.print(binderDeathObjectCount); pw.print(',');
- pw.print(openSslSocketCount); pw.print(',');
// SQL
pw.print(stats.memoryUsed / 1024); pw.print(',');
@@ -1488,8 +1485,7 @@ public final class ActivityThread extends ClientTransactionHandler
printRow(pw, TWO_COUNT_COLUMNS, "Parcel memory:", parcelSize/1024,
"Parcel count:", parcelCount);
printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
- "OpenSSL Sockets:", openSslSocketCount);
- printRow(pw, ONE_COUNT_COLUMN, "WebViews:", webviewInstanceCount);
+ "WebViews:", webviewInstanceCount);
// SQLite mem info
pw.println(" ");
@@ -1562,16 +1558,16 @@ public final class ActivityThread extends ClientTransactionHandler
ContextImpl.class,
Activity.class,
WebView.class,
- OpenSSLSocketImpl.class
+ View.class,
+ ViewRootImpl.class
};
long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
long appContextInstanceCount = instanceCounts[0];
long activityInstanceCount = instanceCounts[1];
long webviewInstanceCount = instanceCounts[2];
- long openSslSocketCount = instanceCounts[3];
+ long viewInstanceCount = instanceCounts[3];
+ long viewRootInstanceCount = instanceCounts[4];
- long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
int globalAssetCount = AssetManager.getGlobalAssetCount();
int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
@@ -1612,8 +1608,6 @@ public final class ActivityThread extends ClientTransactionHandler
proto.write(MemInfoDumpProto.AppData.ObjectStats.PARCEL_COUNT, parcelCount);
proto.write(MemInfoDumpProto.AppData.ObjectStats.BINDER_OBJECT_DEATH_COUNT,
binderDeathObjectCount);
- proto.write(MemInfoDumpProto.AppData.ObjectStats.OPEN_SSL_SOCKET_COUNT,
- openSslSocketCount);
proto.write(MemInfoDumpProto.AppData.ObjectStats.WEBVIEW_INSTANCE_COUNT,
webviewInstanceCount);
proto.end(oToken);
@@ -3431,26 +3425,12 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
- /**
- * Returns {@code true} if the {@link android.app.ActivityManager.ProcessState} of the current
- * process is cached.
- */
- @Override
- @VisibleForTesting
- public boolean isCachedProcessState() {
- synchronized (mAppThread) {
- return mLastProcessState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
- }
- }
-
@Override
public void updateProcessState(int processState, boolean fromIpc) {
- final boolean wasCached;
synchronized (mAppThread) {
if (mLastProcessState == processState) {
return;
}
- wasCached = isCachedProcessState();
mLastProcessState = processState;
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
@@ -3467,22 +3447,6 @@ public final class ActivityThread extends ClientTransactionHandler
+ (fromIpc ? " (from ipc" : ""));
}
}
-
- // Handle the pending configuration if the process state is changed from cached to
- // non-cached. Except the case where there is a launching activity because the
- // LaunchActivityItem will handle it.
- if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
- final Configuration pendingConfig =
- mConfigurationController.getPendingConfiguration(false /* clearPending */);
- if (pendingConfig == null) {
- return;
- }
- if (Looper.myLooper() == mH.getLooper()) {
- handleConfigurationChanged(pendingConfig);
- } else {
- sendMessage(H.CONFIGURATION_CHANGED, pendingConfig);
- }
- }
}
/** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */
@@ -6909,9 +6873,12 @@ public final class ActivityThread extends ClientTransactionHandler
private InstrumentationInfo prepareInstrumentation(AppBindData data) {
final InstrumentationInfo ii;
try {
- ii = new ApplicationPackageManager(null, getPackageManager())
- .getInstrumentationInfo(data.instrumentationName, 0);
- } catch (PackageManager.NameNotFoundException e) {
+ ii = getPackageManager().getInstrumentationInfoAsUser(data.instrumentationName,
+ 0 /* flags */, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ if (ii == null) {
throw new RuntimeException(
"Unable to find instrumentation info for: " + data.instrumentationName);
}
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
index b9ad5c337813..72506b9fcdbb 100644
--- a/core/java/android/app/ActivityThreadInternal.java
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -32,8 +32,6 @@ interface ActivityThreadInternal {
boolean isInDensityCompatMode();
- boolean isCachedProcessState();
-
Application getApplication();
ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index d641a3b469a6..fea30278aabe 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -960,7 +960,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public int checkSignatures(String pkg1, String pkg2) {
try {
- return mPM.checkSignatures(pkg1, pkg2);
+ return mPM.checkSignatures(pkg1, pkg2, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1695,8 +1695,8 @@ public class ApplicationPackageManager extends PackageManager {
ComponentName className, int flags)
throws NameNotFoundException {
try {
- InstrumentationInfo ii = mPM.getInstrumentationInfo(
- className, flags);
+ InstrumentationInfo ii = mPM.getInstrumentationInfoAsUser(
+ className, flags, getUserId());
if (ii != null) {
return ii;
}
@@ -1713,7 +1713,7 @@ public class ApplicationPackageManager extends PackageManager {
String targetPackage, int flags) {
try {
ParceledListSlice<InstrumentationInfo> parceledList =
- mPM.queryInstrumentation(targetPackage, flags);
+ mPM.queryInstrumentationAsUser(targetPackage, flags, getUserId());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -3716,15 +3716,7 @@ public class ApplicationPackageManager extends PackageManager {
throws NameNotFoundException {
Objects.requireNonNull(packageName);
Objects.requireNonNull(propertyName);
- try {
- final Property property = mPM.getProperty(propertyName, packageName, null);
- if (property == null) {
- throw new NameNotFoundException();
- }
- return property;
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
+ return getPropertyAsUser(propertyName, packageName, null /* className */, getUserId());
}
@Override
@@ -3732,9 +3724,18 @@ public class ApplicationPackageManager extends PackageManager {
throws NameNotFoundException {
Objects.requireNonNull(component);
Objects.requireNonNull(propertyName);
+ return getPropertyAsUser(propertyName,
+ component.getPackageName(), component.getClassName(), getUserId());
+ }
+
+ @Override
+ public Property getPropertyAsUser(@NonNull String propertyName, @NonNull String packageName,
+ @Nullable String className, int userId) throws NameNotFoundException {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(propertyName);
try {
- final Property property = mPM.getProperty(
- propertyName, component.getPackageName(), component.getClassName());
+ final Property property = mPM.getPropertyAsUser(propertyName,
+ packageName, className, userId);
if (property == null) {
throw new NameNotFoundException();
}
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index 1a77b65c8ef6..18dc1ce18baf 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -124,12 +124,6 @@ class ConfigurationController {
* @param config The new configuration.
*/
void handleConfigurationChanged(@NonNull Configuration config) {
- if (mActivityThread.isCachedProcessState()) {
- updatePendingConfiguration(config);
- // If the process is in a cached state, delay the handling until the process is no
- // longer cached.
- return;
- }
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
handleConfigurationChanged(config, null /* compat */);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6d982ced385c..4c7bc6da7fb2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2593,7 +2593,8 @@ class ContextImpl extends Context {
try {
return createPackageContextAsUser(getPackageName(), flags, user);
} catch (NameNotFoundException e) {
- throw new IllegalStateException("Own package not found: package=" + getPackageName());
+ throw new IllegalStateException("Own package not found for user "
+ + user.getIdentifier() + ": package=" + getPackageName());
}
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index fe75dd302beb..201473f4957e 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -348,7 +348,6 @@ interface IActivityTaskManager {
/**
* Prepare the back navigation in the server. This setups the leashed for sysui to animate
* the back gesture and returns the data needed for the animation.
- * @param requestAnimation true if the caller wishes to animate the back navigation
*/
- android.window.BackNavigationInfo startBackNavigation(in boolean requestAnimation);
+ android.window.BackNavigationInfo startBackNavigation();
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 28c273ec50a6..167de463ad17 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -211,6 +211,7 @@ interface IWallpaperManager {
*
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)")
oneway void setWallpaperDimAmount(float dimAmount);
/**
@@ -219,6 +220,7 @@ interface IWallpaperManager {
*
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)")
float getWallpaperDimAmount();
/**
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index c802d20a5a57..88c506474419 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -51,6 +51,7 @@ import android.view.IWindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.util.Preconditions;
@@ -758,7 +759,9 @@ public class KeyguardManager {
}
}
- private boolean checkInitialLockMethodUsage() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean checkInitialLockMethodUsage() {
if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) {
throw new SecurityException("Requires SET_INITIAL_LOCK permission.");
}
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index e90bf86f175d..bdab39dcd2ac 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -90,7 +90,7 @@ import java.util.Objects;
* </p>
* <pre>
* MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
+ * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
* if (route != null) {
* Display presentationDisplay = route.getPresentationDisplay();
* if (presentationDisplay != null) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2a1883d5e0bb..d275c8336251 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -365,8 +365,8 @@ public class ResourcesManager {
@NonNull Configuration config) {
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
config.densityDpi = dm.densityDpi;
- config.screenWidthDp = (int) (dm.widthPixels / dm.density);
- config.screenHeightDp = (int) (dm.heightPixels / dm.density);
+ config.screenWidthDp = (int) (dm.widthPixels / dm.density + 0.5f);
+ config.screenHeightDp = (int) (dm.heightPixels / dm.density + 0.5f);
int sl = Configuration.resetScreenLayout(config.screenLayout);
if (dm.widthPixels > dm.heightPixels) {
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 40192836e0a7..6615374f71ec 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -230,6 +230,8 @@ import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
import android.view.displayhash.DisplayHashManager;
import android.view.inputmethod.InputMethodManager;
+import android.view.selectiontoolbar.ISelectionToolbarManager;
+import android.view.selectiontoolbar.SelectionToolbarManager;
import android.view.textclassifier.TextClassificationManager;
import android.view.textservice.TextServicesManager;
import android.view.translation.ITranslationManager;
@@ -363,6 +365,15 @@ public final class SystemServiceRegistry {
return new TextClassificationManager(ctx);
}});
+ registerService(Context.SELECTION_TOOLBAR_SERVICE, SelectionToolbarManager.class,
+ new CachedServiceFetcher<SelectionToolbarManager>() {
+ @Override
+ public SelectionToolbarManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.SELECTION_TOOLBAR_SERVICE);
+ return new SelectionToolbarManager(ctx.getOuterContext(),
+ ISelectionToolbarManager.Stub.asInterface(b));
+ }});
+
registerService(Context.FONT_SERVICE, FontManager.class,
new CachedServiceFetcher<FontManager>() {
@Override
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 32207af22dc1..908d3f802764 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -155,6 +155,23 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.app.KeyguardManagerTest"
+ }
+ ],
+ "file_patterns": [
+ "(/|^)KeyguardManager.java"
+ ]
}
],
"presubmit-large": [
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 7910f1a426c2..b09463e3074b 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -140,13 +140,6 @@ public class TaskInfo {
public LocusId mTopActivityLocusId;
/**
- * True if the task can go in the split-screen primary stack.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean supportsSplitScreenMultiWindow;
-
- /**
* Whether this task supports multi windowing modes based on the device settings and the
* root activity resizability and configuration.
* @hide
@@ -499,7 +492,6 @@ public class TaskInfo {
lastActiveTime = source.readLong();
taskDescription = source.readTypedObject(ActivityManager.TaskDescription.CREATOR);
- supportsSplitScreenMultiWindow = source.readBoolean();
supportsMultiWindow = source.readBoolean();
resizeMode = source.readInt();
configuration.readFromParcel(source);
@@ -546,7 +538,6 @@ public class TaskInfo {
dest.writeLong(lastActiveTime);
dest.writeTypedObject(taskDescription, flags);
- dest.writeBoolean(supportsSplitScreenMultiWindow);
dest.writeBoolean(supportsMultiWindow);
dest.writeInt(resizeMode);
configuration.writeToParcel(dest, flags);
@@ -584,7 +575,6 @@ public class TaskInfo {
+ " realActivity=" + realActivity
+ " numActivities=" + numActivities
+ " lastActiveTime=" + lastActiveTime
- + " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
+ " supportsMultiWindow=" + supportsMultiWindow
+ " resizeMode=" + resizeMode
+ " isResizeable=" + isResizeable
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 5d6e2bda0b83..7964ae904392 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -431,8 +431,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
writeTo.write(buffer, 0, readByteCount);
writeTo.flush();
}
- } catch (IOException ioe) {
- Log.w(TAG, "Error while reading/writing to streams");
+ } catch (IOException ignored) {
} finally {
IoUtils.closeQuietly(readFrom);
IoUtils.closeQuietly(writeTo);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e022ca306674..ea80369983a5 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -67,6 +67,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemProperties;
+import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -558,26 +559,23 @@ public class WallpaperManager {
}
mCachedWallpaper = null;
mCachedWallpaperUserId = 0;
- }
- try {
- Bitmap currentWallpaper = getCurrentWallpaperLocked(
- context, userId, hardware, cmProxy);
- if (currentWallpaper != null) {
- synchronized (this) {
- mCachedWallpaper = currentWallpaper;
- mCachedWallpaperUserId = userId;
- return mCachedWallpaper;
+ try {
+ mCachedWallpaper = getCurrentWallpaperLocked(
+ context, userId, hardware, cmProxy);
+ mCachedWallpaperUserId = userId;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
+ } catch (SecurityException e) {
+ if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O_MR1) {
+ Log.w(TAG, "No permission to access wallpaper, suppressing"
+ + " exception to avoid crashing legacy app.");
+ } else {
+ // Post-O apps really most sincerely need the permission.
+ throw e;
}
}
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
- } catch (SecurityException e) {
- if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O_MR1) {
- Log.w(TAG, "No permission to access wallpaper, suppressing"
- + " exception to avoid crashing legacy app.");
- } else {
- // Post-O apps really most sincerely need the permission.
- throw e;
+ if (mCachedWallpaper != null) {
+ return mCachedWallpaper;
}
}
if (returnDefault) {
@@ -2025,7 +2023,7 @@ public class WallpaperManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)
- public float getWallpaperDimAmount() {
+ public @FloatRange (from = 0f, to = 1f) float getWallpaperDimAmount() {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
@@ -2474,7 +2472,7 @@ public class WallpaperManager {
*
* @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
- * @see android.service.wallpaper.WallpaperService.Engine#onComputeColors()
+ * @see WallpaperService.Engine#onComputeColors()
*/
void onColorsChanged(@Nullable WallpaperColors colors, int which);
@@ -2486,7 +2484,7 @@ public class WallpaperManager {
* @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
* @param userId Owner of the wallpaper
- * @see android.service.wallpaper.WallpaperService.Engine#onComputeColors()
+ * @see WallpaperService.Engine#onComputeColors()
* @hide
*/
default void onColorsChanged(@Nullable WallpaperColors colors, int which, int userId) {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index e96a98697184..d0ea8d41d65c 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -104,19 +104,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
public static final int WINDOWING_MODE_FULLSCREEN = 1;
/** Always on-top (always visible). of other siblings in its parent container. */
public static final int WINDOWING_MODE_PINNED = 2;
- /** The primary container driving the screen to be in split-screen mode. */
- // TODO: Remove once split-screen is migrated to wm-shell.
- public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
- /**
- * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
- * split-screen mode.
- * NOTE: Containers launched with the windowing mode with APIs like
- * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
- * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
- * mode
- */
- // TODO: Remove once split-screen is migrated to wm-shell.
- public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
/** Can be freely resized within its parent container. */
// TODO: Remove once freeform is migrated to wm-shell.
public static final int WINDOWING_MODE_FREEFORM = 5;
@@ -129,8 +116,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_MULTI_WINDOW,
WINDOWING_MODE_PINNED,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
WINDOWING_MODE_FREEFORM,
})
public @interface WindowingMode {}
@@ -890,9 +875,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
}
/**
- * Returns true if this container can be put in either
- * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
- * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
+ * Returns true if this container can be put in {@link #WINDOWING_MODE_MULTI_WINDOW}
+ * windowing mode based on its current state.
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
@@ -911,8 +895,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
case WINDOWING_MODE_MULTI_WINDOW: return "multi-window";
case WINDOWING_MODE_PINNED: return "pinned";
- case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
- case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
case WINDOWING_MODE_FREEFORM: return "freeform";
}
return String.valueOf(windowingMode);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b7f113609188..939763ac811d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -148,8 +148,8 @@ import java.util.function.Consumer;
* <p><b>Note: </b>on
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, some methods can
* throw an {@link UnsafeStateException} exception (for example, if the vehicle is moving), so
- * callers running on automotive builds should wrap every method call under the methods provided by
- * {@code android.car.admin.CarDevicePolicyManager}.
+ * callers running on automotive builds should always check for that exception, otherwise they
+ * might crash.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
@@ -6475,31 +6475,50 @@ public class DevicePolicyManager {
/**
* Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
* indicating that encryption is supported, but is not currently active.
+ * <p>
+ * {@link #getStorageEncryptionStatus} can only return this value on devices that use Full Disk
+ * Encryption. Support for Full Disk Encryption was entirely removed in API level 33, having
+ * been replaced by File Based Encryption. Devices that use File Based Encryption always
+ * automatically activate their encryption on first boot.
+ * <p>
+ * {@link #setStorageEncryption} can still return this value for an unrelated reason, but {@link
+ * #setStorageEncryption} is deprecated since it doesn't do anything useful.
*/
public static final int ENCRYPTION_STATUS_INACTIVE = 1;
/**
- * Result code for {@link #getStorageEncryptionStatus}:
- * indicating that encryption is not currently active, but is currently
- * being activated. This is only reported by devices that support
- * encryption of data and only when the storage is currently
- * undergoing a process of becoming encrypted. A device that must reboot and/or wipe data
- * to become encrypted will never return this value.
+ * Result code for {@link #getStorageEncryptionStatus}: indicating that encryption is not
+ * currently active, but is currently being activated.
+ * <p>
+ * @deprecated This result code has never actually been used, so there is no reason for apps to
+ * check for it.
*/
+ @Deprecated
public static final int ENCRYPTION_STATUS_ACTIVATING = 2;
/**
* Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
* indicating that encryption is active.
* <p>
- * Also see {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
+ * {@link #getStorageEncryptionStatus} can only return this value for apps targeting API level
+ * 23 or lower, or on devices that use Full Disk Encryption. Support for Full Disk Encryption
+ * was entirely removed in API level 33, having been replaced by File Based Encryption. The
+ * result code {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER} is used on devices that use File Based
+ * Encryption, except when the app targets API level 23 or lower.
+ * <p>
+ * {@link #setStorageEncryption} can still return this value for an unrelated reason, but {@link
+ * #setStorageEncryption} is deprecated since it doesn't do anything useful.
*/
public static final int ENCRYPTION_STATUS_ACTIVE = 3;
/**
- * Result code for {@link #getStorageEncryptionStatus}:
- * indicating that encryption is active, but an encryption key has not
- * been set by the user.
+ * Result code for {@link #getStorageEncryptionStatus}: indicating that encryption is active,
+ * but the encryption key is not cryptographically protected by the user's credentials.
+ * <p>
+ * This value can only be returned on devices that use Full Disk Encryption. Support for Full
+ * Disk Encryption was entirely removed in API level 33, having been replaced by File Based
+ * Encryption. With File Based Encryption, each user's credential-encrypted storage is always
+ * cryptographically protected by the user's credentials.
*/
public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4;
diff --git a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
index f5604347065e..0ec825371515 100644
--- a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
+++ b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
@@ -1,4 +1,5 @@
rubinxu@google.com
acjohnston@google.com
pgrafov@google.com
+ayushsha@google.com
alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/core/java/android/app/admin/WorkDeviceExperience_OWNERS b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
index dcacaa25a236..7c90feb1871f 100644
--- a/core/java/android/app/admin/WorkDeviceExperience_OWNERS
+++ b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
@@ -2,4 +2,5 @@ work-device-experience+reviews@google.com
scottjonathan@google.com
arangelov@google.com
kholoudm@google.com
+eliselliott@google.com
alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/core/java/android/app/ambientcontext/AmbientContextManager.java b/core/java/android/app/ambientcontext/AmbientContextManager.java
index 7f913e798bc9..dd1dd0c75f76 100644
--- a/core/java/android/app/ambientcontext/AmbientContextManager.java
+++ b/core/java/android/app/ambientcontext/AmbientContextManager.java
@@ -153,7 +153,7 @@ public final class AmbientContextManager {
* eventTypes.add(AmbientContextEvent.EVENT_SNORE);
*
* // Create Consumer
- * Consumer<Integer> statusConsumer = response -> {
+ * Consumer<Integer> statusConsumer = status -> {
* int status = status.getStatusCode();
* if (status == AmbientContextManager.STATUS_SUCCESS) {
* // Show user it's enabled
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 67f631f98f0b..88a7c0f910d3 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -246,6 +246,9 @@ public class BackupManager {
* new changes to its data. A backup operation using your application's
* {@link android.app.backup.BackupAgent} subclass will be scheduled when you
* call this method.
+ *
+ * <p>
+ * Note: This only works if your application is performing Key/Value backups.
*/
public void dataChanged() {
checkServiceBinder();
@@ -268,6 +271,8 @@ public class BackupManager {
* as the caller.
*
* @param packageName The package name identifying the application to back up.
+ * <p>
+ * Note: Only works for packages performing Key/Value backups.
*/
public static void dataChanged(String packageName) {
checkServiceBinder();
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 6f73d02caa12..f31e2bce84b4 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -33,7 +33,7 @@ interface ISliceManager {
// Perms.
void grantSlicePermission(String callingPkg, String toPkg, in Uri uri);
void revokeSlicePermission(String callingPkg, String toPkg, in Uri uri);
- int checkSlicePermission(in Uri uri, String callingPkg, String pkg, int pid, int uid,
+ int checkSlicePermission(in Uri uri, String callingPkg, int pid, int uid,
in String[] autoGrantPermissions);
void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
}
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 5497b78c3f81..ed4ea749c181 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -439,8 +439,8 @@ public class SliceManager {
*/
public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
try {
- return mService.checkSlicePermission(uri, mContext.getPackageName(), null, pid, uid,
- null);
+ return mService.checkSlicePermission(uri, mContext.getPackageName(), pid, uid,
+ null /* autoGrantPermissions */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -488,17 +488,13 @@ public class SliceManager {
* Does the permission check to see if a caller has access to a specific slice.
* @hide
*/
- public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid,
- String[] autoGrantPermissions) {
+ public void enforceSlicePermission(Uri uri, int pid, int uid, String[] autoGrantPermissions) {
try {
if (UserHandle.isSameApp(uid, Process.myUid())) {
return;
}
- if (pkg == null) {
- throw new SecurityException("No pkg specified");
- }
- int result = mService.checkSlicePermission(uri, mContext.getPackageName(), pkg, pid,
- uid, autoGrantPermissions);
+ int result = mService.checkSlicePermission(uri, mContext.getPackageName(), pid, uid,
+ autoGrantPermissions);
if (result == PERMISSION_DENIED) {
throw new SecurityException("User " + uid + " does not have slice permission for "
+ uri + ".");
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index fb8a83bfc0ef..e6c88a31a1b2 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -452,8 +452,8 @@ public abstract class SliceProvider extends ContentProvider {
String pkg = callingPkg != null ? callingPkg
: getContext().getPackageManager().getNameForUid(callingUid);
try {
- mSliceManager.enforceSlicePermission(sliceUri, pkg,
- callingPid, callingUid, mAutoGrantPermissions);
+ mSliceManager.enforceSlicePermission(sliceUri, callingPid, callingUid,
+ mAutoGrantPermissions);
} catch (SecurityException e) {
return createPermissionSlice(getContext(), sliceUri, pkg);
}
diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java
index c1185584b4ed..a7828ab4c9dc 100644
--- a/core/java/android/app/time/ExternalTimeSuggestion.java
+++ b/core/java/android/app/time/ExternalTimeSuggestion.java
@@ -19,15 +19,14 @@ package android.app.time;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.timedetector.TimeSuggestionHelper;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
@@ -75,7 +74,9 @@ public final class ExternalTimeSuggestion implements Parcelable {
public static final @NonNull Creator<ExternalTimeSuggestion> CREATOR =
new Creator<ExternalTimeSuggestion>() {
public ExternalTimeSuggestion createFromParcel(Parcel in) {
- return ExternalTimeSuggestion.createFromParcel(in);
+ TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+ ExternalTimeSuggestion.class, in);
+ return new ExternalTimeSuggestion(helper);
}
public ExternalTimeSuggestion[] newArray(int size) {
@@ -83,10 +84,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
}
};
- @NonNull
- private final TimestampedValue<Long> mUnixEpochTime;
- @Nullable
- private ArrayList<String> mDebugInfo;
+ @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
/**
* Creates a time suggestion cross-referenced to the elapsed realtime clock. See {@link
@@ -98,17 +96,12 @@ public final class ExternalTimeSuggestion implements Parcelable {
*/
public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis,
@CurrentTimeMillisLong long suggestionMillis) {
- mUnixEpochTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis);
+ mTimeSuggestionHelper = new TimeSuggestionHelper(ExternalTimeSuggestion.class,
+ new TimestampedValue<>(elapsedRealtimeMillis, suggestionMillis));
}
- private static ExternalTimeSuggestion createFromParcel(Parcel in) {
- TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
- ExternalTimeSuggestion suggestion =
- new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue());
- @SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
- suggestion.mDebugInfo = debugInfo;
- return suggestion;
+ private ExternalTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+ mTimeSuggestionHelper = Objects.requireNonNull(helper);
}
@Override
@@ -118,8 +111,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mUnixEpochTime, 0);
- dest.writeList(mDebugInfo);
+ mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
}
/**
@@ -127,7 +119,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
*/
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
- return mUnixEpochTime;
+ return mTimeSuggestionHelper.getUnixEpochTime();
}
/**
@@ -135,9 +127,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
*/
@NonNull
public List<String> getDebugInfo() {
- return mDebugInfo == null
- ? Collections.emptyList()
- : Collections.unmodifiableList(mDebugInfo);
+ return mTimeSuggestionHelper.getDebugInfo();
}
/**
@@ -146,10 +136,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
* #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(@NonNull String... debugInfos) {
- if (mDebugInfo == null) {
- mDebugInfo = new ArrayList<>();
- }
- mDebugInfo.addAll(Arrays.asList(debugInfos));
+ mTimeSuggestionHelper.addDebugInfo(debugInfos);
}
@Override
@@ -161,18 +148,29 @@ public final class ExternalTimeSuggestion implements Parcelable {
return false;
}
ExternalTimeSuggestion that = (ExternalTimeSuggestion) o;
- return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+ return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
}
@Override
public int hashCode() {
- return Objects.hash(mUnixEpochTime);
+ return mTimeSuggestionHelper.hashCode();
}
@Override
public String toString() {
- return "ExternalTimeSuggestion{" + "mUnixEpochTime=" + mUnixEpochTime
- + ", mDebugInfo=" + mDebugInfo
- + '}';
+ return mTimeSuggestionHelper.handleToString();
+ }
+
+ /** @hide */
+ public static ExternalTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ return new ExternalTimeSuggestion(
+ TimeSuggestionHelper.handleParseCommandLineArg(ExternalTimeSuggestion.class, cmd));
+ }
+
+ /** @hide */
+ public static void printCommandLineOpts(PrintWriter pw) {
+ TimeSuggestionHelper.handlePrintCommandLineOpts(
+ pw, "External", ExternalTimeSuggestion.class);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/DummyAppWidget.java b/core/java/android/app/time/ITimeDetectorListener.aidl
index fd99b21c9538..0689647861e5 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/DummyAppWidget.java
+++ b/core/java/android/app/time/ITimeDetectorListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -11,21 +11,12 @@
* 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
+ * limitations under the License.
*/
-package com.android.server.appwidget;
+package android.app.time;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Placeholder widget for testing
- */
-public class DummyAppWidget extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- }
-}
+/** {@hide} */
+oneway interface ITimeDetectorListener {
+ void onChange();
+} \ No newline at end of file
diff --git a/core/java/android/app/time/TimeCapabilities.java b/core/java/android/app/time/TimeCapabilities.java
index fff36c4a7096..9b9dce2bcbe4 100644
--- a/core/java/android/app/time/TimeCapabilities.java
+++ b/core/java/android/app/time/TimeCapabilities.java
@@ -16,7 +16,10 @@
package android.app.time;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.time.Capabilities.CapabilityState;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,40 +57,40 @@ public final class TimeCapabilities implements Parcelable {
*/
@NonNull
private final UserHandle mUserHandle;
- private final @CapabilityState int mConfigureAutoTimeDetectionEnabledCapability;
- private final @CapabilityState int mSuggestTimeManuallyCapability;
+ private final @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+ private final @CapabilityState int mSuggestManualTimeCapability;
private TimeCapabilities(@NonNull Builder builder) {
this.mUserHandle = Objects.requireNonNull(builder.mUserHandle);
- this.mConfigureAutoTimeDetectionEnabledCapability =
+ this.mConfigureAutoDetectionEnabledCapability =
builder.mConfigureAutoDetectionEnabledCapability;
- this.mSuggestTimeManuallyCapability =
- builder.mSuggestTimeManuallyCapability;
+ this.mSuggestManualTimeCapability = builder.mSuggestManualTimeCapability;
}
@NonNull
private static TimeCapabilities createFromParcel(Parcel in) {
UserHandle userHandle = UserHandle.readFromParcel(in);
return new TimeCapabilities.Builder(userHandle)
- .setConfigureAutoTimeDetectionEnabledCapability(in.readInt())
- .setSuggestTimeManuallyCapability(in.readInt())
+ .setConfigureAutoDetectionEnabledCapability(in.readInt())
+ .setSuggestManualTimeCapability(in.readInt())
.build();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
UserHandle.writeToParcel(mUserHandle, dest);
- dest.writeInt(mConfigureAutoTimeDetectionEnabledCapability);
- dest.writeInt(mSuggestTimeManuallyCapability);
+ dest.writeInt(mConfigureAutoDetectionEnabledCapability);
+ dest.writeInt(mSuggestManualTimeCapability);
}
/**
* Returns the capability state associated with the user's ability to modify the automatic time
- * detection setting.
+ * detection setting. The setting can be updated via {@link
+ * TimeManager#updateTimeConfiguration(TimeConfiguration)}.
*/
@CapabilityState
- public int getConfigureAutoTimeDetectionEnabledCapability() {
- return mConfigureAutoTimeDetectionEnabledCapability;
+ public int getConfigureAutoDetectionEnabledCapability() {
+ return mConfigureAutoDetectionEnabledCapability;
}
/**
@@ -95,8 +98,31 @@ public final class TimeCapabilities implements Parcelable {
* device.
*/
@CapabilityState
- public int getSuggestTimeManuallyCapability() {
- return mSuggestTimeManuallyCapability;
+ public int getSuggestManualTimeCapability() {
+ return mSuggestManualTimeCapability;
+ }
+
+ /**
+ * Tries to create a new {@link TimeConfiguration} from the {@code config} and the set of
+ * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is
+ * returned. If the capabilities do not permit one or more of the requested changes then {@code
+ * null} is returned.
+ *
+ * @hide
+ */
+ @Nullable
+ public TimeConfiguration tryApplyConfigChanges(
+ @NonNull TimeConfiguration config,
+ @NonNull TimeConfiguration requestedChanges) {
+ TimeConfiguration.Builder newConfigBuilder = new TimeConfiguration.Builder(config);
+ if (requestedChanges.hasIsAutoDetectionEnabled()) {
+ if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
+ }
+
+ return newConfigBuilder.build();
}
@Override
@@ -109,25 +135,25 @@ public final class TimeCapabilities implements Parcelable {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TimeCapabilities that = (TimeCapabilities) o;
- return mConfigureAutoTimeDetectionEnabledCapability
- == that.mConfigureAutoTimeDetectionEnabledCapability
- && mSuggestTimeManuallyCapability == that.mSuggestTimeManuallyCapability
+ return mConfigureAutoDetectionEnabledCapability
+ == that.mConfigureAutoDetectionEnabledCapability
+ && mSuggestManualTimeCapability == that.mSuggestManualTimeCapability
&& mUserHandle.equals(that.mUserHandle);
}
@Override
public int hashCode() {
- return Objects.hash(mUserHandle, mConfigureAutoTimeDetectionEnabledCapability,
- mSuggestTimeManuallyCapability);
+ return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability,
+ mSuggestManualTimeCapability);
}
@Override
public String toString() {
return "TimeCapabilities{"
+ "mUserHandle=" + mUserHandle
- + ", mConfigureAutoTimeDetectionEnabledCapability="
- + mConfigureAutoTimeDetectionEnabledCapability
- + ", mSuggestTimeManuallyCapability=" + mSuggestTimeManuallyCapability
+ + ", mConfigureAutoDetectionEnabledCapability="
+ + mConfigureAutoDetectionEnabledCapability
+ + ", mSuggestManualTimeCapability=" + mSuggestManualTimeCapability
+ '}';
}
@@ -137,35 +163,32 @@ public final class TimeCapabilities implements Parcelable {
* @hide
*/
public static class Builder {
+
@NonNull private final UserHandle mUserHandle;
private @CapabilityState int mConfigureAutoDetectionEnabledCapability;
- private @CapabilityState int mSuggestTimeManuallyCapability;
+ private @CapabilityState int mSuggestManualTimeCapability;
+
+ public Builder(@NonNull UserHandle userHandle) {
+ this.mUserHandle = Objects.requireNonNull(userHandle);
+ }
public Builder(@NonNull TimeCapabilities timeCapabilities) {
Objects.requireNonNull(timeCapabilities);
this.mUserHandle = timeCapabilities.mUserHandle;
this.mConfigureAutoDetectionEnabledCapability =
- timeCapabilities.mConfigureAutoTimeDetectionEnabledCapability;
- this.mSuggestTimeManuallyCapability =
- timeCapabilities.mSuggestTimeManuallyCapability;
- }
-
- public Builder(@NonNull UserHandle userHandle) {
- this.mUserHandle = Objects.requireNonNull(userHandle);
+ timeCapabilities.mConfigureAutoDetectionEnabledCapability;
+ this.mSuggestManualTimeCapability = timeCapabilities.mSuggestManualTimeCapability;
}
/** Sets the state for automatic time detection config. */
- public Builder setConfigureAutoTimeDetectionEnabledCapability(
- @CapabilityState int setConfigureAutoTimeDetectionEnabledCapability) {
- this.mConfigureAutoDetectionEnabledCapability =
- setConfigureAutoTimeDetectionEnabledCapability;
+ public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) {
+ this.mConfigureAutoDetectionEnabledCapability = value;
return this;
}
/** Sets the state for manual time change. */
- public Builder setSuggestTimeManuallyCapability(
- @CapabilityState int suggestTimeManuallyCapability) {
- this.mSuggestTimeManuallyCapability = suggestTimeManuallyCapability;
+ public Builder setSuggestManualTimeCapability(@CapabilityState int value) {
+ this.mSuggestManualTimeCapability = value;
return this;
}
@@ -173,7 +196,7 @@ public final class TimeCapabilities implements Parcelable {
public TimeCapabilities build() {
verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability,
"configureAutoDetectionEnabledCapability");
- verifyCapabilitySet(mSuggestTimeManuallyCapability, "suggestTimeManuallyCapability");
+ verifyCapabilitySet(mSuggestManualTimeCapability, "mSuggestManualTimeCapability");
return new TimeCapabilities(this);
}
diff --git a/core/java/android/app/time/TimeCapabilitiesAndConfig.java b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
index 71fce14a80b1..be4d01048cee 100644
--- a/core/java/android/app/time/TimeCapabilitiesAndConfig.java
+++ b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
@@ -42,19 +42,18 @@ public final class TimeCapabilitiesAndConfig implements Parcelable {
}
};
- @NonNull
- private final TimeCapabilities mTimeCapabilities;
-
- @NonNull
- private final TimeConfiguration mTimeConfiguration;
+ @NonNull private final TimeCapabilities mCapabilities;
+ @NonNull private final TimeConfiguration mConfiguration;
/**
+ * Creates a new instance.
+ *
* @hide
*/
public TimeCapabilitiesAndConfig(@NonNull TimeCapabilities timeCapabilities,
@NonNull TimeConfiguration timeConfiguration) {
- mTimeCapabilities = Objects.requireNonNull(timeCapabilities);
- mTimeConfiguration = Objects.requireNonNull(timeConfiguration);
+ mCapabilities = Objects.requireNonNull(timeCapabilities);
+ mConfiguration = Objects.requireNonNull(timeConfiguration);
}
@NonNull
@@ -64,14 +63,20 @@ public final class TimeCapabilitiesAndConfig implements Parcelable {
return new TimeCapabilitiesAndConfig(capabilities, configuration);
}
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mCapabilities, flags);
+ dest.writeParcelable(mConfiguration, flags);
+ }
+
/**
* Returns the user's time behaviour capabilities.
*
* @hide
*/
@NonNull
- public TimeCapabilities getTimeCapabilities() {
- return mTimeCapabilities;
+ public TimeCapabilities getCapabilities() {
+ return mCapabilities;
}
/**
@@ -80,8 +85,8 @@ public final class TimeCapabilitiesAndConfig implements Parcelable {
* @hide
*/
@NonNull
- public TimeConfiguration getTimeConfiguration() {
- return mTimeConfiguration;
+ public TimeConfiguration getConfiguration() {
+ return mConfiguration;
}
@Override
@@ -90,30 +95,24 @@ public final class TimeCapabilitiesAndConfig implements Parcelable {
}
@Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mTimeCapabilities, flags);
- dest.writeParcelable(mTimeConfiguration, flags);
- }
-
- @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TimeCapabilitiesAndConfig that = (TimeCapabilitiesAndConfig) o;
- return mTimeCapabilities.equals(that.mTimeCapabilities)
- && mTimeConfiguration.equals(that.mTimeConfiguration);
+ return mCapabilities.equals(that.mCapabilities)
+ && mConfiguration.equals(that.mConfiguration);
}
@Override
public int hashCode() {
- return Objects.hash(mTimeCapabilities, mTimeConfiguration);
+ return Objects.hash(mCapabilities, mConfiguration);
}
@Override
public String toString() {
return "TimeCapabilitiesAndConfig{"
- + "mTimeCapabilities=" + mTimeCapabilities
- + ", mTimeConfiguration=" + mTimeConfiguration
+ + "mCapabilities=" + mCapabilities
+ + ", mConfiguration=" + mConfiguration
+ '}';
}
}
diff --git a/core/java/android/app/time/TimeConfiguration.java b/core/java/android/app/time/TimeConfiguration.java
index 70aede034d27..11f6ed2a9f88 100644
--- a/core/java/android/app/time/TimeConfiguration.java
+++ b/core/java/android/app/time/TimeConfiguration.java
@@ -27,8 +27,16 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
- * User visible settings that control the behavior of the time zone detector / manual time zone
- * entry.
+ * User visible settings that control the behavior of the time detector / manual time entry.
+ *
+ * <p>When reading the configuration, values for all settings will be provided. In some cases, such
+ * as when the device behavior relies on optional hardware / OEM configuration, or the value of
+ * several settings, the device behavior may not be directly affected by the setting value.
+ *
+ * <p>Settings can be left absent when updating configuration via {@link
+ * TimeManager#updateTimeConfiguration(TimeConfiguration)} and those settings will not be
+ * changed. Not all configuration settings can be modified by all users: see {@link
+ * TimeManager#getTimeCapabilitiesAndConfig()} and {@link TimeCapabilities} for details.
*
* @hide
*/
@@ -61,29 +69,53 @@ public final class TimeConfiguration implements Parcelable {
this.mBundle = builder.mBundle;
}
+ private static TimeConfiguration readFromParcel(Parcel in) {
+ return new TimeConfiguration.Builder()
+ .setPropertyBundleInternal(in.readBundle())
+ .build();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBundle(mBundle);
+ }
+
+ /**
+ * Returns {@code true} if all known settings are present.
+ *
+ * @hide
+ */
+ public boolean isComplete() {
+ return hasIsAutoDetectionEnabled();
+ }
+
/**
* Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This
* controls whether a device will attempt to determine the time automatically using
* contextual information if the device supports auto detection.
+ *
+ * <p>See {@link TimeCapabilities#getConfigureAutoDetectionEnabledCapability()} for how to
+ * tell if the setting is meaningful for the current user at this time.
+ *
+ * @throws IllegalStateException if the setting is not present
*/
public boolean isAutoDetectionEnabled() {
+ enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
}
- @Override
- public int describeContents() {
- return 0;
+ /**
+ * Returns {@code true} if the {@link #isAutoDetectionEnabled()} setting is present.
+ *
+ * @hide
+ */
+ public boolean hasIsAutoDetectionEnabled() {
+ return mBundle.containsKey(SETTING_AUTO_DETECTION_ENABLED);
}
@Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeBundle(mBundle);
- }
-
- private static TimeConfiguration readFromParcel(Parcel in) {
- return new TimeConfiguration.Builder()
- .merge(in.readBundle())
- .build();
+ public int describeContents() {
+ return 0;
}
@Override
@@ -106,33 +138,59 @@ public final class TimeConfiguration implements Parcelable {
+ '}';
}
+ private void enforceSettingPresent(@TimeZoneConfiguration.Setting String setting) {
+ if (!mBundle.containsKey(setting)) {
+ throw new IllegalStateException(setting + " is not set");
+ }
+ }
+
/**
* A builder for {@link TimeConfiguration} objects.
*
* @hide
*/
public static final class Builder {
+
private final Bundle mBundle = new Bundle();
+ /**
+ * Creates a new Builder with no settings held.
+ */
public Builder() {}
- public Builder(@NonNull TimeConfiguration configuration) {
- mBundle.putAll(configuration.mBundle);
+ /**
+ * Creates a new Builder by copying the settings from an existing instance.
+ */
+ public Builder(@NonNull TimeConfiguration toCopy) {
+ mergeProperties(toCopy);
}
- /** Sets whether auto detection is enabled or not. */
+ /**
+ * Merges {@code other} settings into this instances, replacing existing values in this
+ * where the settings appear in both.
+ *
+ * @hide
+ */
@NonNull
- public Builder setAutoDetectionEnabled(boolean enabled) {
- mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
+ public Builder mergeProperties(@NonNull TimeConfiguration toCopy) {
+ mBundle.putAll(toCopy.mBundle);
+ return this;
+ }
+
+ @NonNull
+ Builder setPropertyBundleInternal(@NonNull Bundle bundle) {
+ this.mBundle.putAll(bundle);
return this;
}
- Builder merge(@NonNull Bundle bundle) {
- mBundle.putAll(bundle);
+ /** Sets whether auto detection is enabled or not. */
+ @NonNull
+ public Builder setAutoDetectionEnabled(boolean enabled) {
+ mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
return this;
}
- /** Returns {@link TimeConfiguration} object. */
+ /** Returns the {@link TimeConfiguration}. */
@NonNull
public TimeConfiguration build() {
return new TimeConfiguration(this);
diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java
index 463e5f081c4f..3531b19d0f65 100644
--- a/core/java/android/app/timedetector/GnssTimeSuggestion.java
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java
@@ -17,30 +17,19 @@
package android.app.timedetector;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
/**
* A time signal from a GNSS source.
*
- * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code
- * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code
- * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate
- * but it is volatile, so time suggestions cannot be persisted across device resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was entered. This information exists only to aid in
- * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
*
* @hide
*/
@@ -49,7 +38,9 @@ public final class GnssTimeSuggestion implements Parcelable {
public static final @NonNull Creator<GnssTimeSuggestion> CREATOR =
new Creator<GnssTimeSuggestion>() {
public GnssTimeSuggestion createFromParcel(Parcel in) {
- return GnssTimeSuggestion.createFromParcel(in);
+ TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+ GnssTimeSuggestion.class, in);
+ return new GnssTimeSuggestion(helper);
}
public GnssTimeSuggestion[] newArray(int size) {
@@ -57,23 +48,14 @@ public final class GnssTimeSuggestion implements Parcelable {
}
};
- @NonNull private final TimestampedValue<Long> mUnixEpochTime;
- @Nullable private ArrayList<String> mDebugInfo;
+ @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
public GnssTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
- mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
- Objects.requireNonNull(unixEpochTime.getValue());
+ mTimeSuggestionHelper = new TimeSuggestionHelper(GnssTimeSuggestion.class, unixEpochTime);
}
- private static GnssTimeSuggestion createFromParcel(Parcel in) {
- TimestampedValue<Long> unixEpochTime =
- in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
- GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime);
- @SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
- null /* classLoader */, java.lang.String.class);
- suggestion.mDebugInfo = debugInfo;
- return suggestion;
+ private GnssTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+ mTimeSuggestionHelper = Objects.requireNonNull(helper);
}
@Override
@@ -83,19 +65,17 @@ public final class GnssTimeSuggestion implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mUnixEpochTime, 0);
- dest.writeList(mDebugInfo);
+ mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
}
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
- return mUnixEpochTime;
+ return mTimeSuggestionHelper.getUnixEpochTime();
}
@NonNull
public List<String> getDebugInfo() {
- return mDebugInfo == null
- ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ return mTimeSuggestionHelper.getDebugInfo();
}
/**
@@ -104,10 +84,7 @@ public final class GnssTimeSuggestion implements Parcelable {
* {@link #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
- if (mDebugInfo == null) {
- mDebugInfo = new ArrayList<>();
- }
- mDebugInfo.addAll(Arrays.asList(debugInfos));
+ mTimeSuggestionHelper.addDebugInfo(debugInfos);
}
@Override
@@ -119,19 +96,29 @@ public final class GnssTimeSuggestion implements Parcelable {
return false;
}
GnssTimeSuggestion that = (GnssTimeSuggestion) o;
- return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+ return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
}
@Override
public int hashCode() {
- return Objects.hash(mUnixEpochTime);
+ return mTimeSuggestionHelper.hashCode();
}
@Override
public String toString() {
- return "GnssTimeSuggestion{"
- + "mUnixEpochTime=" + mUnixEpochTime
- + ", mDebugInfo=" + mDebugInfo
- + '}';
+ return mTimeSuggestionHelper.handleToString();
+ }
+
+ /** Parses command line args to create a {@link GnssTimeSuggestion}. */
+ public static GnssTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ TimeSuggestionHelper suggestionHelper =
+ TimeSuggestionHelper.handleParseCommandLineArg(GnssTimeSuggestion.class, cmd);
+ return new GnssTimeSuggestion(suggestionHelper);
+ }
+
+ /** Prints the command line args needed to create a {@link GnssTimeSuggestion}. */
+ public static void printCommandLineOpts(PrintWriter pw) {
+ TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "GNSS", GnssTimeSuggestion.class);
}
}
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index 9a6c33589123..fc7afb483142 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -17,6 +17,7 @@
package android.app.timedetector;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.ITimeDetectorListener;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
@@ -39,6 +40,9 @@ import android.app.timedetector.TelephonyTimeSuggestion;
*/
interface ITimeDetectorService {
TimeCapabilitiesAndConfig getCapabilitiesAndConfig();
+ void addListener(ITimeDetectorListener listener);
+ void removeListener(ITimeDetectorListener listener);
+
boolean updateConfiguration(in TimeConfiguration timeConfiguration);
void suggestExternalTime( in ExternalTimeSuggestion timeSuggestion);
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 247d97190d0c..b447799eb84c 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -20,27 +20,17 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
/**
* A time signal from a manual (user provided) source.
*
- * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code unixEpochTime.referenceTimeMillis}
- * is the value of the elapsed realtime clock when the {@code unixEpochTime.value} was established.
- * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
- * suggestions cannot be persisted across device resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was entered. This information exists only to aid in
- * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
*
* @hide
*/
@@ -49,7 +39,9 @@ public final class ManualTimeSuggestion implements Parcelable {
public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
new Creator<ManualTimeSuggestion>() {
public ManualTimeSuggestion createFromParcel(Parcel in) {
- return ManualTimeSuggestion.createFromParcel(in);
+ TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+ ManualTimeSuggestion.class, in);
+ return new ManualTimeSuggestion(helper);
}
public ManualTimeSuggestion[] newArray(int size) {
@@ -57,23 +49,14 @@ public final class ManualTimeSuggestion implements Parcelable {
}
};
- @NonNull private final TimestampedValue<Long> mUnixEpochTime;
- @Nullable private ArrayList<String> mDebugInfo;
+ @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
public ManualTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
- mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
- Objects.requireNonNull(unixEpochTime.getValue());
+ mTimeSuggestionHelper = new TimeSuggestionHelper(ManualTimeSuggestion.class, unixEpochTime);
}
- private static ManualTimeSuggestion createFromParcel(Parcel in) {
- TimestampedValue<Long> unixEpochTime =
- in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
- ManualTimeSuggestion suggestion = new ManualTimeSuggestion(unixEpochTime);
- @SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
- null /* classLoader */, java.lang.String.class);
- suggestion.mDebugInfo = debugInfo;
- return suggestion;
+ private ManualTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+ mTimeSuggestionHelper = Objects.requireNonNull(helper);
}
@Override
@@ -83,19 +66,17 @@ public final class ManualTimeSuggestion implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mUnixEpochTime, 0);
- dest.writeList(mDebugInfo);
+ mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
}
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
- return mUnixEpochTime;
+ return mTimeSuggestionHelper.getUnixEpochTime();
}
@NonNull
public List<String> getDebugInfo() {
- return mDebugInfo == null
- ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ return mTimeSuggestionHelper.getDebugInfo();
}
/**
@@ -104,10 +85,7 @@ public final class ManualTimeSuggestion implements Parcelable {
* {@link #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
- if (mDebugInfo == null) {
- mDebugInfo = new ArrayList<>();
- }
- mDebugInfo.addAll(Arrays.asList(debugInfos));
+ mTimeSuggestionHelper.addDebugInfo(debugInfos);
}
@Override
@@ -119,19 +97,28 @@ public final class ManualTimeSuggestion implements Parcelable {
return false;
}
ManualTimeSuggestion that = (ManualTimeSuggestion) o;
- return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+ return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
}
@Override
public int hashCode() {
- return Objects.hash(mUnixEpochTime);
+ return mTimeSuggestionHelper.hashCode();
}
@Override
public String toString() {
- return "ManualTimeSuggestion{"
- + "mUnixEpochTime=" + mUnixEpochTime
- + ", mDebugInfo=" + mDebugInfo
- + '}';
+ return mTimeSuggestionHelper.handleToString();
+ }
+
+ /** @hide */
+ public static ManualTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ return new ManualTimeSuggestion(
+ TimeSuggestionHelper.handleParseCommandLineArg(ManualTimeSuggestion.class, cmd));
+ }
+
+ /** @hide */
+ public static void printCommandLineOpts(PrintWriter pw) {
+ TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Manual", ManualTimeSuggestion.class);
}
}
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index f620bc912ec9..e93c75cb0a0c 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -17,31 +17,19 @@
package android.app.timedetector;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
/**
* A time signal from a network time source like NTP.
*
- * <p>{@code unixEpochTime} contains the suggested time. The {@code unixEpochTime.value} is the
- * number of milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system.
- * The {@code unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when
- * the {@code unixEpochTime.value} was established. Note that the elapsed realtime clock is
- * considered accurate but it is volatile, so time suggestions cannot be persisted across device
- * resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was determined. This information exists only to aid
- * in debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
*
* @hide
*/
@@ -50,7 +38,9 @@ public final class NetworkTimeSuggestion implements Parcelable {
public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR =
new Creator<NetworkTimeSuggestion>() {
public NetworkTimeSuggestion createFromParcel(Parcel in) {
- return NetworkTimeSuggestion.createFromParcel(in);
+ TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+ NetworkTimeSuggestion.class, in);
+ return new NetworkTimeSuggestion(helper);
}
public NetworkTimeSuggestion[] newArray(int size) {
@@ -58,23 +48,15 @@ public final class NetworkTimeSuggestion implements Parcelable {
}
};
- @NonNull private final TimestampedValue<Long> mUnixEpochTime;
- @Nullable private ArrayList<String> mDebugInfo;
+ @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
- mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
- Objects.requireNonNull(unixEpochTime.getValue());
+ mTimeSuggestionHelper = new TimeSuggestionHelper(
+ NetworkTimeSuggestion.class, unixEpochTime);
}
- private static NetworkTimeSuggestion createFromParcel(Parcel in) {
- TimestampedValue<Long> unixEpochTime =
- in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
- NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(unixEpochTime);
- @SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
- null /* classLoader */, java.lang.String.class);
- suggestion.mDebugInfo = debugInfo;
- return suggestion;
+ private NetworkTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+ mTimeSuggestionHelper = Objects.requireNonNull(helper);
}
@Override
@@ -84,35 +66,30 @@ public final class NetworkTimeSuggestion implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mUnixEpochTime, 0);
- dest.writeList(mDebugInfo);
+ mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
}
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
- return mUnixEpochTime;
+ return mTimeSuggestionHelper.getUnixEpochTime();
}
@NonNull
public List<String> getDebugInfo() {
- return mDebugInfo == null
- ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ return mTimeSuggestionHelper.getDebugInfo();
}
/**
* Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * information is present in {@link #toString()} but is not considered for {@link
+ * #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
- if (mDebugInfo == null) {
- mDebugInfo = new ArrayList<>();
- }
- mDebugInfo.addAll(Arrays.asList(debugInfos));
+ mTimeSuggestionHelper.addDebugInfo(debugInfos);
}
@Override
- public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
if (this == o) {
return true;
}
@@ -120,19 +97,28 @@ public final class NetworkTimeSuggestion implements Parcelable {
return false;
}
NetworkTimeSuggestion that = (NetworkTimeSuggestion) o;
- return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+ return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
}
@Override
public int hashCode() {
- return Objects.hash(mUnixEpochTime);
+ return mTimeSuggestionHelper.hashCode();
}
@Override
public String toString() {
- return "NetworkTimeSuggestion{"
- + "mUnixEpochTime=" + mUnixEpochTime
- + ", mDebugInfo=" + mDebugInfo
- + '}';
+ return mTimeSuggestionHelper.handleToString();
+ }
+
+ /** @hide */
+ public static NetworkTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ return new NetworkTimeSuggestion(
+ TimeSuggestionHelper.handleParseCommandLineArg(NetworkTimeSuggestion.class, cmd));
+ }
+
+ /** @hide */
+ public static void printCommandLineOpts(PrintWriter pw) {
+ TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Network", NetworkTimeSuggestion.class);
}
}
diff --git a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
index 1fa392a701d1..e0347c07e52a 100644
--- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
@@ -20,8 +20,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -90,6 +92,61 @@ public final class TelephonyTimeSuggestion implements Parcelable {
return suggestion;
}
+ /** @hide */
+ public static TelephonyTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ Integer slotIndex = null;
+ Long referenceTimeMillis = null;
+ Long unixEpochTimeMillis = null;
+ String opt;
+ while ((opt = cmd.getNextArg()) != null) {
+ switch (opt) {
+ case "--slot_index": {
+ slotIndex = Integer.parseInt(cmd.getNextArgRequired());
+ break;
+ }
+ case "--reference_time": {
+ referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+ break;
+ }
+ case "--unix_epoch_time": {
+ unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+ }
+
+ if (slotIndex == null) {
+ throw new IllegalArgumentException("No slotIndex specified.");
+ }
+ if (referenceTimeMillis == null) {
+ throw new IllegalArgumentException("No referenceTimeMillis specified.");
+ }
+ if (unixEpochTimeMillis == null) {
+ throw new IllegalArgumentException("No unixEpochTimeMillis specified.");
+ }
+
+ TimestampedValue<Long> timeSignal =
+ new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis);
+ Builder builder = new Builder(slotIndex)
+ .setUnixEpochTime(timeSignal)
+ .addDebugInfo("Command line injection");
+ return builder.build();
+ }
+
+ /** @hide */
+ public static void printCommandLineOpts(PrintWriter pw) {
+ pw.println("Telephony suggestion options:");
+ pw.println(" --slot_index <number>");
+ pw.println(" --reference_time <elapsed realtime millis>");
+ pw.println(" --unix_epoch_time <Unix epoch time millis>");
+ pw.println();
+ pw.println("See " + TelephonyTimeSuggestion.class.getName() + " for more information");
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index a3562301cde7..f0d777611620 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -44,6 +44,36 @@ public interface TimeDetector {
String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled";
/**
+ * A shell command that injects a manual time suggestion.
+ * @hide
+ */
+ String SHELL_COMMAND_SUGGEST_MANUAL_TIME = "suggest_manual_time";
+
+ /**
+ * A shell command that injects a telephony time suggestion.
+ * @hide
+ */
+ String SHELL_COMMAND_SUGGEST_TELEPHONY_TIME = "suggest_telephony_time";
+
+ /**
+ * A shell command that injects a network time suggestion.
+ * @hide
+ */
+ String SHELL_COMMAND_SUGGEST_NETWORK_TIME = "suggest_network_time";
+
+ /**
+ * A shell command that injects a GNSS time suggestion.
+ * @hide
+ */
+ String SHELL_COMMAND_SUGGEST_GNSS_TIME = "suggest_gnss_time";
+
+ /**
+ * A shell command that injects a external time suggestion.
+ * @hide
+ */
+ String SHELL_COMMAND_SUGGEST_EXTERNAL_TIME = "suggest_external_time";
+
+ /**
* A shared utility method to create a {@link ManualTimeSuggestion}.
*
* @hide
diff --git a/core/java/android/app/timedetector/TimeSuggestionHelper.java b/core/java/android/app/timedetector/TimeSuggestionHelper.java
new file mode 100644
index 000000000000..9b99be61b3c8
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeSuggestionHelper.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.ShellCommand;
+import android.os.TimestampedValue;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A delegate class to support time suggestion classes that could diverge in the future. This class
+ * exists purely for code re-use and provides support methods. It avoids class inheritance
+ * deliberately to allow each suggestion to evolve in different directions later without affecting
+ * SDK APIs.
+ *
+ * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code
+ * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code
+ * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate
+ * but it is volatile, so time suggestions cannot be persisted across device resets.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was entered. This information exists only to aid in
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
+ * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ *
+ * @hide
+ */
+public final class TimeSuggestionHelper {
+
+ @NonNull private final Class<?> mHelpedClass;
+ @NonNull private final TimestampedValue<Long> mUnixEpochTime;
+ @Nullable private ArrayList<String> mDebugInfo;
+
+ /** Creates a helper for the specified class, containing the supplied properties. */
+ public TimeSuggestionHelper(@NonNull Class<?> helpedClass,
+ @NonNull TimestampedValue<Long> unixEpochTime) {
+ mHelpedClass = Objects.requireNonNull(helpedClass);
+ mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
+ Objects.requireNonNull(unixEpochTime.getValue());
+ }
+
+ /** See {@link TimeSuggestionHelper} for property details. */
+ @NonNull
+ public TimestampedValue<Long> getUnixEpochTime() {
+ return mUnixEpochTime;
+ }
+
+ /** See {@link TimeSuggestionHelper} for information about {@code debugInfo}. */
+ @NonNull
+ public List<String> getDebugInfo() {
+ return mDebugInfo == null
+ ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}.
+ */
+ public void addDebugInfo(@NonNull String debugInfo) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.add(debugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ addDebugInfo(Arrays.asList(debugInfos));
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}.
+ */
+ public void addDebugInfo(@NonNull List<String> debugInfo) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>(debugInfo.size());
+ }
+ mDebugInfo.addAll(debugInfo);
+ }
+
+ /**
+ * Implemented in case users call this insteam of {@link #handleEquals(TimeSuggestionHelper)}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TimeSuggestionHelper that = (TimeSuggestionHelper) o;
+ return handleEquals(that);
+ }
+
+ /** Used to implement {@link Object#equals(Object)}. */
+ public boolean handleEquals(TimeSuggestionHelper o) {
+ return Objects.equals(mHelpedClass, o.mHelpedClass)
+ && Objects.equals(mUnixEpochTime, o.mUnixEpochTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUnixEpochTime);
+ }
+
+ /** Used to implement {@link Object#toString()}. */
+ public String handleToString() {
+ return mHelpedClass.getSimpleName() + "{"
+ + "mUnixEpochTime=" + mUnixEpochTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+
+ /** Constructs a helper with suggestion state from a Parcel. */
+ public static TimeSuggestionHelper handleCreateFromParcel(@NonNull Class<?> helpedClass,
+ @NonNull Parcel in) {
+ @SuppressWarnings("unchecked")
+ TimestampedValue<Long> unixEpochTime = in.readParcelable(
+ null /* classLoader */, TimestampedValue.class);
+ TimeSuggestionHelper suggestionHelper =
+ new TimeSuggestionHelper(helpedClass, unixEpochTime);
+ suggestionHelper.mDebugInfo = in.readArrayList(null /* classLoader */, String.class);
+ return suggestionHelper;
+ }
+
+ /** Writes the helper suggestion state to a Parcel. */
+ public void handleWriteToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mUnixEpochTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ /** Parses command line args to create a {@link TimeSuggestionHelper}. */
+ public static TimeSuggestionHelper handleParseCommandLineArg(
+ @NonNull Class<?> helpedClass, @NonNull ShellCommand cmd)
+ throws IllegalArgumentException {
+ Long referenceTimeMillis = null;
+ Long unixEpochTimeMillis = null;
+ String opt;
+ while ((opt = cmd.getNextArg()) != null) {
+ switch (opt) {
+ case "--reference_time": {
+ referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+ break;
+ }
+ case "--unix_epoch_time": {
+ unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+ }
+
+ if (referenceTimeMillis == null) {
+ throw new IllegalArgumentException("No referenceTimeMillis specified.");
+ }
+ if (unixEpochTimeMillis == null) {
+ throw new IllegalArgumentException("No unixEpochTimeMillis specified.");
+ }
+
+ TimestampedValue<Long> timeSignal =
+ new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis);
+ TimeSuggestionHelper suggestionHelper = new TimeSuggestionHelper(helpedClass, timeSignal);
+ suggestionHelper.addDebugInfo("Command line injection");
+ return suggestionHelper;
+ }
+
+ /** Prints the command line args needed to create a {@link TimeSuggestionHelper}. */
+ public static void handlePrintCommandLineOpts(
+ @NonNull PrintWriter pw, @NonNull String typeName, @NonNull Class<?> clazz) {
+ pw.printf("%s suggestion options:\n", typeName);
+ pw.println(" --reference_time <elapsed realtime millis>");
+ pw.println(" --unix_epoch_time <Unix epoch time millis>");
+ pw.println();
+ pw.println("See " + clazz.getName() + " for more information");
+ }
+}
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 6e3bbccdbef0..8545aa71b4d7 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -161,7 +161,22 @@ public class AppHibernationManager {
public @NonNull Map<String, HibernationStats> getHibernationStatsForUser() {
try {
return mIAppHibernationService.getHibernationStatsForUser(
- null /* packageNames */, mContext.getUserId());
+ null /* packageNames */, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Whether global hibernation should delete ART ahead-of-time compilation artifacts
+ * and prevent package manager from re-optimizing the APK.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
+ public boolean isOatArtifactDeletionEnabled() {
+ try {
+ return mIAppHibernationService.isOatArtifactDeletionEnabled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
index 11bb6b505cdf..d70930305d11 100644
--- a/core/java/android/apphibernation/IAppHibernationService.aidl
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -30,4 +30,6 @@ interface IAppHibernationService {
List<String> getHibernatingPackagesForUser(int userId);
Map<String, HibernationStats> getHibernationStatsForUser(in List<String> packageNames,
int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION)")
+ boolean isOatArtifactDeletionEnabled();
} \ No newline at end of file
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 18c638112480..966347fb2edb 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -42,12 +42,15 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.BackgroundThread;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Updates AppWidget state; gets information about installed AppWidget providers and other
@@ -63,6 +66,7 @@ import java.util.List;
@RequiresFeature(PackageManager.FEATURE_APP_WIDGETS)
public class AppWidgetManager {
+
/**
* Activity action to launch from your {@link AppWidgetHost} activity when you want to
* pick an AppWidget to display. The AppWidget picker activity will be launched.
@@ -332,6 +336,17 @@ public class AppWidgetManager {
public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
/**
+ * A combination broadcast of APPWIDGET_ENABLED and APPWIDGET_UPDATE.
+ * Sent during boot time and when the host is binding the widget for the very first time
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
+ public static final String ACTION_APPWIDGET_ENABLE_AND_UPDATE = "android.appwidget.action"
+ + ".APPWIDGET_ENABLE_AND_UPDATE";
+
+ /**
* Sent when the custom extras for an AppWidget change.
*
* <p class="note">This is a protected intent that can only be sent
@@ -456,6 +471,8 @@ public class AppWidgetManager {
public static final String ACTION_APPWIDGET_HOST_RESTORED
= "android.appwidget.action.APPWIDGET_HOST_RESTORED";
+ private static final String TAG = "AppWidgetManager";
+
/**
* An intent extra that contains multiple appWidgetIds. These are id values as
* they were provided to the application during a recent restore from backup. It is
@@ -511,6 +528,26 @@ public class AppWidgetManager {
mPackageName = context.getOpPackageName();
mService = service;
mDisplayMetrics = context.getResources().getDisplayMetrics();
+ if (mService == null) {
+ return;
+ }
+ BackgroundThread.getExecutor().execute(() -> {
+ try {
+ mService.notifyProviderInheritance(getInstalledProvidersForPackage(mPackageName,
+ null)
+ .stream().filter(Objects::nonNull)
+ .map(info -> info.provider).filter(p -> {
+ try {
+ Class clazz = Class.forName(p.getClassName());
+ return AppWidgetProvider.class.isAssignableFrom(clazz);
+ } catch (Exception e) {
+ return false;
+ }
+ }).toArray(ComponentName[]::new));
+ } catch (Exception e) {
+ Log.e(TAG, "Nofity service of inheritance info", e);
+ }
+ });
}
/**
diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java
index a5d2198a6e17..3344ebc083a2 100644
--- a/core/java/android/appwidget/AppWidgetProvider.java
+++ b/core/java/android/appwidget/AppWidgetProvider.java
@@ -58,7 +58,12 @@ public class AppWidgetProvider extends BroadcastReceiver {
// Protect against rogue update broadcasts (not really a security issue,
// just filter bad broacasts out so subclasses are less likely to crash).
String action = intent.getAction();
- if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ if (AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE.equals(action)) {
+ this.onReceive(context, new Intent(intent)
+ .setAction(AppWidgetManager.ACTION_APPWIDGET_ENABLED));
+ this.onReceive(context, new Intent(intent)
+ .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE));
+ } else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
Bundle extras = intent.getExtras();
if (extras != null) {
int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 2e94dd1a47c4..4d2317a6d0f4 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -355,6 +355,9 @@ public class AppWidgetProviderInfo implements Parcelable {
@UnsupportedAppUsage
public ActivityInfo providerInfo;
+ /** @hide */
+ public boolean isExtendedFromAppWidgetProvider;
+
public AppWidgetProviderInfo() {
}
@@ -387,6 +390,7 @@ public class AppWidgetProviderInfo implements Parcelable {
this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR);
this.widgetFeatures = in.readInt();
this.descriptionRes = in.readInt();
+ this.isExtendedFromAppWidgetProvider = in.readBoolean();
}
/**
@@ -510,6 +514,7 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeTypedObject(this.providerInfo, flags);
out.writeInt(this.widgetFeatures);
out.writeInt(this.descriptionRes);
+ out.writeBoolean(this.isExtendedFromAppWidgetProvider);
}
@Override
@@ -539,6 +544,7 @@ public class AppWidgetProviderInfo implements Parcelable {
that.providerInfo = this.providerInfo;
that.widgetFeatures = this.widgetFeatures;
that.descriptionRes = this.descriptionRes;
+ that.isExtendedFromAppWidgetProvider = this.isExtendedFromAppWidgetProvider;
return that;
}
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
index 439df4b86cf0..554b0de82b40 100644
--- a/core/java/android/appwidget/OWNERS
+++ b/core/java/android/appwidget/OWNERS
@@ -1,3 +1,4 @@
pinyaoting@google.com
+sihua@google.com
suprabh@google.com
sunnygoyal@google.com
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 257530b26eec..75ab11531595 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -151,7 +151,7 @@ public final class AssociationRequest implements Parcelable {
* The Display name of the device to be shown in the CDM confirmation UI. Must be non-null for
* "self-managed" association.
*/
- private final @Nullable CharSequence mDisplayName;
+ private @Nullable CharSequence mDisplayName;
/**
* Whether the association is to be managed by the companion application.
@@ -302,6 +302,11 @@ public final class AssociationRequest implements Parcelable {
}
/** @hide */
+ public void setDisplayName(CharSequence displayName) {
+ mDisplayName = displayName;
+ }
+
+ /** @hide */
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public List<DeviceFilter<?>> getDeviceFilters() {
@@ -597,7 +602,9 @@ public final class AssociationRequest implements Parcelable {
boolean forceConfirmation = (flg & 0x20) != 0;
boolean skipPrompt = (flg & 0x400) != 0;
List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
- in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader(), (Class<android.companion.DeviceFilter<?>>) (Class<?>) android.companion.DeviceFilter.class);
+ in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader(),
+ (Class<android.companion.DeviceFilter<?>>) (Class<?>)
+ android.companion.DeviceFilter.class);
String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
CharSequence displayName = (flg & 0x8) == 0 ? null : (CharSequence) in.readCharSequence();
String packageName = (flg & 0x40) == 0 ? null : in.readString();
@@ -641,10 +648,10 @@ public final class AssociationRequest implements Parcelable {
};
@DataClass.Generated(
- time = 1643238443303L,
+ time = 1649179640045L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
- inputSignatures = "public static final java.lang.String DEVICE_PROFILE_WATCH\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_APP_STREAMING\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_AUTOMOTIVE_PROJECTION\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_COMPUTER\nprivate final boolean mSingleDevice\nprivate final @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate final @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate final @android.annotation.Nullable java.lang.CharSequence mDisplayName\nprivate final boolean mSelfManaged\nprivate final boolean mForceConfirmation\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.UserIdInt int mUserId\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate final long mCreationTime\nprivate boolean mSkipPrompt\npublic @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String getDeviceProfile()\npublic @android.annotation.Nullable java.lang.CharSequence getDisplayName()\npublic boolean isSelfManaged()\npublic boolean isForceConfirmation()\npublic boolean isSingleDevice()\npublic void setPackageName(java.lang.String)\npublic void setUserId(int)\npublic void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic void setSkipPrompt(boolean)\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.CharSequence mDisplayName\nprivate boolean mSelfManaged\nprivate boolean mForceConfirmation\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDisplayName(java.lang.CharSequence)\npublic @android.annotation.RequiresPermission @android.annotation.NonNull android.companion.AssociationRequest.Builder setSelfManaged(boolean)\npublic @android.annotation.RequiresPermission @android.annotation.NonNull android.companion.AssociationRequest.Builder setForceConfirmation(boolean)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genConstDefs=false)")
+ inputSignatures = "public static final java.lang.String DEVICE_PROFILE_WATCH\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_APP_STREAMING\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_AUTOMOTIVE_PROJECTION\npublic static final @android.annotation.RequiresPermission java.lang.String DEVICE_PROFILE_COMPUTER\nprivate final boolean mSingleDevice\nprivate final @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate final @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.CharSequence mDisplayName\nprivate final boolean mSelfManaged\nprivate final boolean mForceConfirmation\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.UserIdInt int mUserId\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate final long mCreationTime\nprivate boolean mSkipPrompt\npublic @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String getDeviceProfile()\npublic @android.annotation.Nullable java.lang.CharSequence getDisplayName()\npublic boolean isSelfManaged()\npublic boolean isForceConfirmation()\npublic boolean isSingleDevice()\npublic void setPackageName(java.lang.String)\npublic void setUserId(int)\npublic void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic void setSkipPrompt(boolean)\npublic void setDisplayName(java.lang.CharSequence)\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.CharSequence mDisplayName\nprivate boolean mSelfManaged\nprivate boolean mForceConfirmation\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDisplayName(java.lang.CharSequence)\npublic @android.annotation.RequiresPermission @android.annotation.NonNull android.companion.AssociationRequest.Builder setSelfManaged(boolean)\npublic @android.annotation.RequiresPermission @android.annotation.NonNull android.companion.AssociationRequest.Builder setForceConfirmation(boolean)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 56939f0ae650..14c671f32c21 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -774,7 +774,8 @@ public final class CompanionDeviceManager {
}
/**
- * Dispatch a message to system for processing.
+ * Dispatch a message to system for processing. It should only be called by
+ * {@link CompanionDeviceService#dispatchMessageToSystem(int, int, byte[])}
*
* <p>Calling app must declare uses-permission
* {@link android.Manifest.permission#DELIVER_COMPANION_MESSAGES}</p>
@@ -874,6 +875,67 @@ public final class CompanionDeviceManager {
}
}
+ /**
+ * Build a permission sync user consent dialog.
+ *
+ * <p>Only the companion app which owns the association can call this method. Otherwise a null
+ * IntentSender will be returned from this method and an error will be logged.
+ * The The app should launch the {@link Activity} in the returned {@code intentSender}
+ * {@link IntentSender} by calling
+ * {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}.</p>
+ *
+ * <p>The permission transfer doesn't happen immediately after the call or user consented.
+ * The app needs to trigger the system data transfer manually by calling
+ * {@link #startSystemDataTransfer(int)}, when it confirms the communication channel between
+ * the two devices is established.</p>
+ *
+ * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the association
+ * of the companion device recorded by CompanionDeviceManager
+ * @return An {@link IntentSender} that the app should use to launch the UI for
+ * the user to confirm the system data transfer request.
+ */
+ @UserHandleAware
+ @Nullable
+ public IntentSender buildPermissionTransferUserConsentIntent(int associationId)
+ throws DeviceNotAssociatedException {
+ try {
+ PendingIntent pendingIntent = mService.buildPermissionTransferUserConsentIntent(
+ mContext.getOpPackageName(),
+ mContext.getUserId(),
+ associationId);
+ if (pendingIntent == null) {
+ return null;
+ }
+ return pendingIntent.getIntentSender();
+ } catch (RemoteException e) {
+ ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Start system data transfer which has been previously approved by the user.
+ *
+ * <p>Before calling this method, the app needs to make sure there's a communication channel
+ * between two devices, and has prompted user consent dialogs built by one of these methods:
+ * {@link #buildPermissionTransferUserConsentIntent(int)}.
+ * The transfer may fail if the communication channel is disconnected during the transfer.</p>
+ *
+ * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the Association
+ * of the companion device recorded by CompanionDeviceManager
+ * @throws DeviceNotAssociatedException Exception if the companion device is not associated
+ */
+ @UserHandleAware
+ public void startSystemDataTransfer(int associationId) throws DeviceNotAssociatedException {
+ try {
+ mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(),
+ associationId);
+ } catch (RemoteException e) {
+ ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private boolean checkFeaturePresent() {
boolean featurePresent = mService != null;
if (!featurePresent && DEBUG) {
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 9e1bf4bb9484..791fc2aaa2cb 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.util.Log;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A service that receives calls from the system when the associated companion device appears
@@ -152,11 +153,9 @@ public abstract class CompanionDeviceService extends Service {
* @param messageId system assigned id of the message to be sent
* @param associationId association id of the associated device
* @param message message to be sent
- *
- * @hide
*/
- @MainThread
- public void onDispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+ public void onMessageDispatchedFromSystem(int messageId, int associationId,
+ @NonNull byte[] message) {
// do nothing. Companion apps can override this function for system to send messages.
}
@@ -167,17 +166,38 @@ public abstract class CompanionDeviceService extends Service {
* <p>Calling app must declare uses-permission
* {@link android.Manifest.permission#DELIVER_COMPANION_MESSAGES}</p>
*
+ * <p>You need to start the service before calling this method, otherwise the system can't
+ * get the context and the dispatch would fail.</p>
+ *
+ * <p>Note 1: messageId was assigned by the system, and sender should send the messageId along
+ * with the message to the receiver. messageId will later be used for verification purpose.
+ * Misusing the messageId will result in no action.</p>
+ *
+ * <p>Note 2: associationId should be local to your device which is calling this API. It's not
+ * the associationId on your remote device. If you don't have one, you can call
+ * {@link CompanionDeviceManager#associate(AssociationRequest, Executor,
+ * CompanionDeviceManager.Callback)} to create one. Misusing the associationId will result in
+ * {@link DeviceNotAssociatedException}.</p>
+ *
* @param messageId id of the message
* @param associationId id of the associated device
- * @param message messaged received from the associated device
- *
- * @hide
+ * @param message message received from the associated device
*/
@RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
- public final void dispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+ public final void dispatchMessageToSystem(int messageId, int associationId,
+ @NonNull byte[] message)
+ throws DeviceNotAssociatedException {
+ if (getBaseContext() == null) {
+ Log.e(LOG_TAG, "Dispatch failed. Start your service before calling this method.");
+ return;
+ }
CompanionDeviceManager companionDeviceManager =
getSystemService(CompanionDeviceManager.class);
- companionDeviceManager.dispatchMessage(messageId, associationId, message);
+ if (companionDeviceManager != null) {
+ companionDeviceManager.dispatchMessage(messageId, associationId, message);
+ } else {
+ Log.e(LOG_TAG, "CompanionDeviceManager is null. Can't dispatch messages.");
+ }
}
/**
@@ -239,9 +259,11 @@ public abstract class CompanionDeviceService extends Service {
}
@Override
- public void onDispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+ public void onMessageDispatchedFromSystem(int messageId, int associationId,
+ @NonNull byte[] message) {
mMainHandler.postAtFrontOfQueue(
- () -> mService.onDispatchMessage(messageId, associationId, message));
+ () -> mService.onMessageDispatchedFromSystem(messageId, associationId,
+ message));
}
}
}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 68a6031f543f..085fd1b4c388 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -62,7 +62,7 @@ interface ICompanionDeviceManager {
void createAssociation(in String packageName, in String macAddress, int userId,
in byte[] certificate);
- void dispatchMessage(in int messageId, in int associationId, in byte[] message);
+ void dispatchMessage(int messageId, int associationId, in byte[] message);
void addOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId);
@@ -71,4 +71,9 @@ interface ICompanionDeviceManager {
void notifyDeviceAppeared(int associationId);
void notifyDeviceDisappeared(int associationId);
+
+ PendingIntent buildPermissionTransferUserConsentIntent(String callingPackage, int userId,
+ int associationId);
+
+ void startSystemDataTransfer(String packageName, int userId, int associationId);
}
diff --git a/core/java/android/companion/ICompanionDeviceService.aidl b/core/java/android/companion/ICompanionDeviceService.aidl
index 4e453573f62e..3c90b86ca8c0 100644
--- a/core/java/android/companion/ICompanionDeviceService.aidl
+++ b/core/java/android/companion/ICompanionDeviceService.aidl
@@ -22,5 +22,5 @@ import android.companion.AssociationInfo;
oneway interface ICompanionDeviceService {
void onDeviceAppeared(in AssociationInfo associationInfo);
void onDeviceDisappeared(in AssociationInfo associationInfo);
- void onDispatchMessage(in int messageId, in int associationId, in byte[] message);
+ void onMessageDispatchedFromSystem(in int messageId, in int associationId, in byte[] message);
}
diff --git a/core/java/android/companion/SystemDataTransferRequest.java b/core/java/android/companion/SystemDataTransferRequest.java
deleted file mode 100644
index e3b0369e203d..000000000000
--- a/core/java/android/companion/SystemDataTransferRequest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2022 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.companion;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.OneTimeUseBuilder;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A request for users to allow the companion app to transfer system data to the companion devices.
- *
- * @hide
- */
-public final class SystemDataTransferRequest implements Parcelable {
-
- private final int mAssociationId;
- private final boolean mPermissionSyncAllPackages;
- private final List<String> mPermissionSyncPackages;
-
- /**
- * @hide
- */
- public SystemDataTransferRequest(int associationId, boolean syncAllPackages,
- @Nullable List<String> permissionSyncPackages) {
- mAssociationId = associationId;
- mPermissionSyncAllPackages = syncAllPackages;
- mPermissionSyncPackages = permissionSyncPackages;
- }
-
- public int getAssociationId() {
- return mAssociationId;
- }
-
- @NonNull
- public boolean isPermissionSyncAllPackages() {
- return mPermissionSyncAllPackages;
- }
-
- @NonNull
- public List<String> getPermissionSyncPackages() {
- return mPermissionSyncPackages;
- }
-
- /**
- * A builder for {@link SystemDataTransferRequest}.
- *
- * <p>You have to call one of the below methods to create a valid request</p>
- * <br>1. {@link #setPermissionSyncAllPackages()}
- * <br>2. {@link #setPermissionSyncPackages(List)}
- */
- public static final class Builder extends OneTimeUseBuilder<SystemDataTransferRequest> {
-
- private final int mAssociationId;
- private boolean mPermissionSyncAllPackages;
- private List<String> mPermissionSyncPackages = new ArrayList<>();
-
- public Builder(int associationId) {
- mAssociationId = associationId;
- }
-
- /**
- * Call to sync permissions for all the packages. You can optionally call
- * {@link #setPermissionSyncPackages(List)} to specify the packages to sync permissions.
- *
- * <p>The system will only sync permissions that are explicitly granted by the user.</p>
- *
- * <p>If a permission is granted or revoked by the system or a policy, even if the user has
- * explicitly granted or revoked the permission earlier, the permission will be ignored.</p>
- *
- * <p>If a system or policy granted or revoked permission is granted or revoked by the user
- * later, the permission will be ignored.</p>
- *
- * @see #setPermissionSyncPackages(List)
- *
- * @return the builder
- */
- @NonNull
- public Builder setPermissionSyncAllPackages() {
- mPermissionSyncAllPackages = true;
- return this;
- }
-
- /**
- * Set a list of packages to sync permissions. You can optionally call
- * {@link #setPermissionSyncAllPackages()} to sync permissions for all the packages.
- *
- * @see #setPermissionSyncAllPackages()
- *
- * @param permissionSyncPackages packages to sync permissions
- * @return builder
- */
- @NonNull
- public Builder setPermissionSyncPackages(@NonNull List<String> permissionSyncPackages) {
- mPermissionSyncPackages = permissionSyncPackages;
- return this;
- }
-
- @Override
- @NonNull
- public SystemDataTransferRequest build() {
- return new SystemDataTransferRequest(mAssociationId, mPermissionSyncAllPackages,
- mPermissionSyncPackages);
- }
- }
-
- SystemDataTransferRequest(Parcel in) {
- mAssociationId = in.readInt();
- mPermissionSyncAllPackages = in.readBoolean();
- mPermissionSyncPackages = Arrays.asList(in.createString8Array());
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mAssociationId);
- dest.writeBoolean(mPermissionSyncAllPackages);
- dest.writeString8Array(mPermissionSyncPackages.toArray(new String[0]));
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull
- public static final Creator<SystemDataTransferRequest> CREATOR =
- new Creator<SystemDataTransferRequest>() {
- @Override
- public SystemDataTransferRequest createFromParcel(Parcel in) {
- return new SystemDataTransferRequest(in);
- }
-
- @Override
- public SystemDataTransferRequest[] newArray(int size) {
- return new SystemDataTransferRequest[size];
- }
- };
-}
diff --git a/core/java/android/companion/SystemDataTransferRequest.aidl b/core/java/android/companion/datatransfer/PermissionSyncRequest.aidl
index 19ae60effa7a..76a92e33e544 100644
--- a/core/java/android/companion/SystemDataTransferRequest.aidl
+++ b/core/java/android/companion/datatransfer/PermissionSyncRequest.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.companion;
+package android.companion.datatransfer;
-parcelable SystemDataTransferRequest;
+parcelable PermissionSyncRequest;
diff --git a/core/java/android/companion/datatransfer/PermissionSyncRequest.java b/core/java/android/companion/datatransfer/PermissionSyncRequest.java
new file mode 100644
index 000000000000..973fca30c765
--- /dev/null
+++ b/core/java/android/companion/datatransfer/PermissionSyncRequest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The permission sync request class.
+ *
+ * @hide
+ */
+public class PermissionSyncRequest extends SystemDataTransferRequest implements Parcelable {
+
+ /** @hide */
+ public PermissionSyncRequest(int associationId) {
+ super(associationId, DATA_TYPE_PERMISSION_SYNC);
+ }
+
+ /** @hide */
+ @Override
+ public String toString() {
+ return "SystemDataTransferRequest("
+ + "associationId=" + mAssociationId
+ + ", userId=" + mUserId
+ + ", isUserConsented=" + mUserConsented
+ + ")";
+ }
+
+ /** @hide */
+ PermissionSyncRequest(Parcel in) {
+ super(in);
+ }
+
+ /** @hide */
+ @NonNull
+ public static final Creator<PermissionSyncRequest> CREATOR =
+ new Creator<PermissionSyncRequest>() {
+ @Override
+ public PermissionSyncRequest createFromParcel(Parcel in) {
+ return new PermissionSyncRequest(in);
+ }
+
+ @Override
+ public PermissionSyncRequest[] newArray(int size) {
+ return new PermissionSyncRequest[size];
+ }
+ };
+}
diff --git a/core/java/android/companion/datatransfer/SystemDataTransferRequest.java b/core/java/android/companion/datatransfer/SystemDataTransferRequest.java
new file mode 100644
index 000000000000..38a553d8a725
--- /dev/null
+++ b/core/java/android/companion/datatransfer/SystemDataTransferRequest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.Parcel;
+
+/**
+ * A request for users to allow the companion app to transfer system data to the companion devices.
+ *
+ * @hide
+ */
+public abstract class SystemDataTransferRequest {
+
+ /** @hide */
+ public static final int DATA_TYPE_PERMISSION_SYNC = 1;
+
+ final int mAssociationId;
+
+ final int mDataType;
+
+ /**
+ * User id that the request belongs to.
+ * Populated by the system.
+ */
+ @UserIdInt
+ int mUserId;
+
+ /**
+ * Whether the request is consented by the user.
+ * Populated by the system
+ */
+ boolean mUserConsented = false;
+
+ /** @hide */
+ SystemDataTransferRequest(int associationId, int dataType) {
+ mAssociationId = associationId;
+ mDataType = dataType;
+ }
+
+ /** @hide */
+ public int getAssociationId() {
+ return mAssociationId;
+ }
+
+ /** @hide */
+ public int getDataType() {
+ return mDataType;
+ }
+
+ /** @hide */
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /** @hide */
+ public boolean isUserConsented() {
+ return mUserConsented;
+ }
+
+ /** @hide */
+ public void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /** @hide */
+ public void setUserConsented(boolean isUserConsented) {
+ mUserConsented = isUserConsented;
+ }
+
+ /** @hide */
+ SystemDataTransferRequest(Parcel in) {
+ mAssociationId = in.readInt();
+ mDataType = in.readInt();
+ mUserId = in.readInt();
+ mUserConsented = in.readBoolean();
+ }
+
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mAssociationId);
+ dest.writeInt(mDataType);
+ dest.writeInt(mUserId);
+ dest.writeBoolean(mUserConsented);
+ }
+
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 1c9713df972a..3e43cebafdc4 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -13,3 +13,4 @@ per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
per-file ComponentCallbacksController = file:/services/core/java/com/android/server/wm/OWNERS
per-file ComponentCallbacksController = charlesccchen@google.com
+per-file AttributionSource* = file:/core/java/android/permission/OWNERS
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index c193868fc3fd..de6dc22a862e 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -68,7 +68,7 @@ public interface SharedPreferences {
* {@link android.os.Build.VERSION_CODES#R Android R} or later, will receive
* a {@code null} value when preferences are cleared.
*/
- void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
+ void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key);
}
/**
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0673b3ad5b0a..a3d595ef6575 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -106,6 +106,24 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public @interface LaunchMode {
}
+ /** @hide */
+ public static String launchModeToString(@LaunchMode int launchMode) {
+ switch(launchMode) {
+ case LAUNCH_MULTIPLE:
+ return "LAUNCH_MULTIPLE";
+ case LAUNCH_SINGLE_TOP:
+ return "LAUNCH_SINGLE_TOP";
+ case LAUNCH_SINGLE_TASK:
+ return "LAUNCH_SINGLE_TASK";
+ case LAUNCH_SINGLE_INSTANCE:
+ return "LAUNCH_SINGLE_INSTANCE";
+ case LAUNCH_SINGLE_INSTANCE_PER_TASK:
+ return "LAUNCH_SINGLE_INSTANCE_PER_TASK";
+ default:
+ return "unknown=" + launchMode;
+ }
+ }
+
/**
* The launch mode style requested by the activity. From the
* {@link android.R.attr#launchMode} attribute.
@@ -1585,7 +1603,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
+ " persistableMode=" + persistableModeToString());
}
if (launchMode != 0 || flags != 0 || privateFlags != 0 || theme != 0) {
- pw.println(prefix + "launchMode=" + launchMode
+ pw.println(prefix + "launchMode=" + launchModeToString(launchMode)
+ " flags=0x" + Integer.toHexString(flags)
+ " privateFlags=0x" + Integer.toHexString(privateFlags)
+ " theme=0x" + Integer.toHexString(theme));
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 54d57a1b24d9..2ef1c78474f2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -89,8 +89,8 @@ interface IPackageManager {
ActivityInfo getActivityInfo(in ComponentName className, long flags, int userId);
- boolean activitySupportsIntent(in ComponentName className, in Intent intent,
- String resolvedType);
+ boolean activitySupportsIntentAsUser(in ComponentName className, in Intent intent,
+ String resolvedType, int userId);
ActivityInfo getReceiverInfo(in ComponentName className, long flags, int userId);
@@ -100,8 +100,7 @@ interface IPackageManager {
boolean isProtectedBroadcast(String actionName);
- @UnsupportedAppUsage
- int checkSignatures(String pkg1, String pkg2);
+ int checkSignatures(String pkg1, String pkg2, int userId);
@UnsupportedAppUsage
int checkUidSignatures(int uid1, int uid2);
@@ -202,13 +201,11 @@ interface IPackageManager {
ParceledListSlice queryContentProviders(
String processName, int uid, long flags, String metaDataKey);
- @UnsupportedAppUsage
- InstrumentationInfo getInstrumentationInfo(
- in ComponentName className, int flags);
+ InstrumentationInfo getInstrumentationInfoAsUser(
+ in ComponentName className, int flags, int userId);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- ParceledListSlice queryInstrumentation(
- String targetPackage, int flags);
+ ParceledListSlice queryInstrumentationAsUser(
+ String targetPackage, int flags, int userId);
void finishPackageInstall(int token, boolean didLaunch);
@@ -620,7 +617,6 @@ interface IPackageManager {
VerifierDeviceIdentity getVerifierDeviceIdentity();
boolean isFirstBoot();
- boolean isOnlyCoreApps();
boolean isDeviceUpgrading();
/** Reflects current DeviceStorageMonitorService state */
@@ -750,7 +746,7 @@ interface IPackageManager {
// We need to keep these in IPackageManager for app compatibility
//------------------------------------------------------------------------
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- String[] getAppOpPermissionPackages(String permissionName);
+ String[] getAppOpPermissionPackages(String permissionName, int userId);
@UnsupportedAppUsage
PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
@@ -797,7 +793,8 @@ interface IPackageManager {
void holdLock(in IBinder token, in int durationMs);
- PackageManager.Property getProperty(String propertyName, String packageName, String className);
+ PackageManager.Property getPropertyAsUser(String propertyName, String packageName,
+ String className, int userId);
ParceledListSlice queryProperty(String propertyName, int componentType);
void setKeepUninstalledPackages(in List<String> packageList);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index f4de82946253..970849373fb4 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -448,6 +448,12 @@ public class PackageInfo implements Parcelable {
*/
public boolean isApex;
+ /**
+ * Whether this is an active APEX package.
+ * @hide
+ */
+ public boolean isActiveApex;
+
public PackageInfo() {
}
@@ -534,6 +540,7 @@ public class PackageInfo implements Parcelable {
dest.writeInt(0);
}
dest.writeBoolean(isApex);
+ dest.writeBoolean(isActiveApex);
dest.restoreAllowSquashing(prevAllowSquashing);
}
@@ -598,5 +605,6 @@ public class PackageInfo implements Parcelable {
signingInfo = SigningInfo.CREATOR.createFromParcel(source);
}
isApex = source.readBoolean();
+ isActiveApex = source.readBoolean();
}
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 236c24475844..5f45c342a27c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -682,7 +682,9 @@ public class PackageInstaller {
* </ul>
*
* @param packageName The package to uninstall.
- * @param statusReceiver Where to deliver the result.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*
* @see android.app.admin.DevicePolicyManager
*/
@@ -700,7 +702,9 @@ public class PackageInstaller {
*
* @param packageName The package to uninstall.
* @param flags Flags for uninstall.
- * @param statusReceiver Where to deliver the result.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*
* @hide
*/
@@ -725,7 +729,9 @@ public class PackageInstaller {
* </ul>
*
* @param versionedPackage The versioned package to uninstall.
- * @param statusReceiver Where to deliver the result.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*
* @see android.app.admin.DevicePolicyManager
*/
@@ -747,7 +753,9 @@ public class PackageInstaller {
*
* @param versionedPackage The versioned package to uninstall.
* @param flags Flags for uninstall.
- * @param statusReceiver Where to deliver the result.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*
* @hide
*/
@@ -775,7 +783,9 @@ public class PackageInstaller {
*
* @param packageName The package to install.
* @param installReason Reason for install.
- * @param statusReceiver Where to deliver the result.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*/
@RequiresPermission(allOf = {
Manifest.permission.INSTALL_PACKAGES,
@@ -797,8 +807,10 @@ public class PackageInstaller {
* Uninstall the given package for the user for which this installer was created if the package
* will still exist for other users on the device.
*
- * @param packageName The package to install.
- * @param statusReceiver Where to deliver the result.
+ * @param packageName The package to uninstall.
+ * @param statusReceiver Where to deliver the result of the operation indicated by the extra
+ * {@link #EXTRA_STATUS}. Refer to the individual status codes
+ * on how to handle them.
*/
@RequiresPermission(Manifest.permission.DELETE_PACKAGES)
public void uninstallExistingPackage(@NonNull String packageName,
@@ -1705,20 +1717,22 @@ public class PackageInstaller {
public @interface UserActionRequirement {}
/**
- * The installer did not call {@link SessionParams#setRequireUserAction(int)} to
- * specify whether user action should be required for the install.
+ * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
+ * to indicate that user action is unspecified for this install.
+ * {@code requireUserAction} also defaults to this value unless modified by
+ * {@link SessionParams#setRequireUserAction(int)}
*/
public static final int USER_ACTION_UNSPECIFIED = 0;
/**
- * The installer called {@link SessionParams#setRequireUserAction(int)} with
- * {@code true} to require user action for the install to complete.
+ * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
+ * to indicate that user action is required for this install.
*/
public static final int USER_ACTION_REQUIRED = 1;
/**
- * The installer called {@link SessionParams#setRequireUserAction(int)} with
- * {@code false} to request that user action not be required for this install.
+ * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
+ * to indicate that user action is not required for this install.
*/
public static final int USER_ACTION_NOT_REQUIRED = 2;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a90f6d625c51..53c23f3fffa7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2160,14 +2160,6 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_PROCESS_NOT_DEFINED = -122;
/**
- * Installation parse return code: system is in a minimal boot state, and the parser only
- * allows the package with {@code coreApp} manifest attribute to be a valid application.
- *
- * @hide
- */
- public static final int INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED = -123;
-
- /**
* Installation failed return code: the {@code resources.arsc} of one of the APKs being
* installed is compressed or not aligned on a 4-byte boundary. Resource tables that cannot be
* memory mapped exert excess memory pressure on the system and drastically slow down
@@ -4247,6 +4239,7 @@ public abstract class PackageManager {
*/
public static final String EXTRA_VERIFICATION_PACKAGE_NAME
= "android.content.pm.extra.VERIFICATION_PACKAGE_NAME";
+
/**
* Extra field name for the result of a verification, either
* {@link #VERIFICATION_ALLOW}, or {@link #VERIFICATION_REJECT}.
@@ -4256,6 +4249,14 @@ public abstract class PackageManager {
= "android.content.pm.extra.VERIFICATION_RESULT";
/**
+ * Extra field name for tracking whether user action
+ * was requested for a particular install, either {@code true} or {@code false}.
+ * @hide
+ */
+ public static final String EXTRA_USER_ACTION_REQUIRED
+ = "android.content.pm.extra.USER_ACTION_REQUIRED";
+
+ /**
* Extra field name for the version code of a package pending verification.
* @deprecated Use {@link #EXTRA_VERIFICATION_LONG_VERSION_CODE} instead.
* @hide
@@ -4265,8 +4266,7 @@ public abstract class PackageManager {
= "android.content.pm.extra.VERIFICATION_VERSION_CODE";
/**
- * Extra field name for the long version code of a package pending verification.
- *
+ * Extra field name for the long version code of a package pending verification
* @hide
*/
public static final String EXTRA_VERIFICATION_LONG_VERSION_CODE =
@@ -10225,6 +10225,21 @@ public abstract class PackageManager {
}
/**
+ * If the provided className is {@code null}, returns the property defined on the application.
+ * Otherwise, returns the property defined on the component.
+ *
+ * @throws NameNotFoundException if the given package is not installed on the calling user or
+ * component does not exist or if the given property is not defined within the manifest.
+ * @hide
+ */
+ @NonNull
+ public Property getPropertyAsUser(@NonNull String propertyName, @NonNull String packageName,
+ @Nullable String className, int userId) throws NameNotFoundException {
+ throw new UnsupportedOperationException(
+ "getPropertyAsUser not implemented in subclass");
+ }
+
+ /**
* Returns the property definition for all &lt;application&gt; tags.
* <p>If the property is not defined with any &lt;application&gt; tag,
* returns and empty list.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 52e64e80e6d4..44dc28d2b0fa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2618,15 +2618,6 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Package requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2698,15 +2689,6 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Package requires min development platform " + minCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index d6e13ac90f82..9baa6ba2fb49 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -143,6 +143,22 @@ public class UserInfo implements Parcelable {
public static final int FLAG_PROFILE = 0x00001000;
/**
+ * Indicates that this user is created in ephemeral mode via
+ * {@link IUserManager} create user.
+ *
+ * When a user is created with {@link #FLAG_EPHEMERAL}, {@link #FLAG_EPHEMERAL_ON_CREATE}
+ * is set internally within the user manager.
+ *
+ * When {@link #FLAG_EPHEMERAL_ON_CREATE} is set {@link IUserManager.setUserEphemeral}
+ * has no effect because a user that was created ephemeral can never be made non-ephemeral.
+ *
+ * {@link #FLAG_EPHEMERAL_ON_CREATE} should NOT be set by client's of user manager
+ *
+ * @hide
+ */
+ public static final int FLAG_EPHEMERAL_ON_CREATE = 0x00002000;
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = "FLAG_", value = {
@@ -158,7 +174,8 @@ public class UserInfo implements Parcelable {
FLAG_DEMO,
FLAG_FULL,
FLAG_SYSTEM,
- FLAG_PROFILE
+ FLAG_PROFILE,
+ FLAG_EPHEMERAL_ON_CREATE
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserInfoFlag {
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8cc4cdb955ca..d2d00b237a0d 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,15 +316,6 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Parsed package requires min development platform " + minCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -377,29 +368,16 @@ public class FrameworkParsingPackageUtils {
return input.success(targetVers);
}
+ if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
// If it's a pre-release SDK and the codename matches this platform, it
// definitely targets this SDK.
if (matchTargetCode(platformSdkCodenames, targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Parsed package requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
- try {
- if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
- } catch (IllegalArgumentException e) {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
diff --git a/core/java/android/hardware/IConsumerIrService.aidl b/core/java/android/hardware/IConsumerIrService.aidl
index c79bd1958226..930c73f0ae44 100644
--- a/core/java/android/hardware/IConsumerIrService.aidl
+++ b/core/java/android/hardware/IConsumerIrService.aidl
@@ -19,8 +19,13 @@ package android.hardware;
/** {@hide} */
interface IConsumerIrService
{
+ @RequiresNoPermission
boolean hasIrEmitter();
+
+ @EnforcePermission("TRANSMIT_IR")
void transmit(String packageName, int carrierFrequency, in int[] pattern);
+
+ @EnforcePermission("TRANSMIT_IR")
int[] getCarrierFrequencies();
}
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 691690c09e0e..5b1973ad2dd4 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -1234,6 +1234,42 @@ public abstract class CameraCaptureSession implements AutoCloseable {
}
/**
+ * This method is called when the camera device has started reading out the output
+ * image for the request, at the beginning of the sensor image readout.
+ *
+ * <p>For a capture request, this callback is invoked right after
+ * {@link #onCaptureStarted}. Unlike {@link #onCaptureStarted}, instead of passing
+ * a timestamp of start of exposure, this callback passes a timestamp of start of
+ * camera data readout. This is useful because for a camera running at fixed frame
+ * rate, the start of readout is at fixed interval, which is not necessarily true for
+ * the start of exposure, particularly when autoexposure is changing exposure duration
+ * between frames.</p>
+ *
+ * <p>This timestamp may not match {@link CaptureResult#SENSOR_TIMESTAMP the result
+ * timestamp field}. It will, however, match the timestamp of buffers sent to the
+ * output surfaces with {@link OutputConfiguration#TIMESTAMP_BASE_READOUT_SENSOR}
+ * timestamp base.</p>
+ *
+ * <p>This callback will be called only if {@link
+ * CameraCharacteristics#SENSOR_READOUT_TIMESTAMP} is
+ * {@link CameraMetadata#SENSOR_READOUT_TIMESTAMP_HARDWARE}, and it's called
+ * right after {@link #onCaptureStarted}.</p>
+ *
+ * @param session the session returned by {@link CameraDevice#createCaptureSession}
+ * @param request the request for the readout that just began
+ * @param timestamp the timestamp at start of readout for a regular request, or
+ * the timestamp at the input image's start of readout for a
+ * reprocess request, in nanoseconds.
+ * @param frameNumber the frame number for this capture
+ *
+ * @hide
+ */
+ public void onReadoutStarted(@NonNull CameraCaptureSession session,
+ @NonNull CaptureRequest request, long timestamp, long frameNumber) {
+ // default empty implementation
+ }
+
+ /**
* This method is called when some results from an image capture are
* available.
*
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a90eb88bc109..9a719ca9ab98 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -4384,6 +4384,40 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<android.graphics.Rect[]>("android.sensor.opticalBlackRegions", android.graphics.Rect[].class);
/**
+ * <p>Whether or not the camera device supports readout timestamp and
+ * onReadoutStarted callback.</p>
+ * <p>If this tag is HARDWARE, the camera device calls onReadoutStarted in addition to the
+ * onCaptureStarted callback for each capture. The timestamp passed into the callback
+ * is the start of camera image readout rather than the start of the exposure. In
+ * addition, the application can configure an
+ * {@link android.hardware.camera2.params.OutputConfiguration } with
+ * TIMESTAMP_BASE_READOUT_SENSOR timestamp base, in which case, the timestamp of the
+ * output surface matches the timestamp from the corresponding onReadoutStarted callback.</p>
+ * <p>The readout timestamp is beneficial for video recording, because the encoder favors
+ * uniform timestamps, and the readout timestamps better reflect the cadence camera sensors
+ * output data.</p>
+ * <p>If this tag is HARDWARE, the camera device produces the start-of-exposure and
+ * start-of-readout together. As a result, the onReadoutStarted is called right after
+ * onCaptureStarted. The difference in start-of-readout and start-of-exposure is the sensor
+ * exposure time, plus certain constant offset. The offset is usually due to camera sensor
+ * level crop, and it remains constant for a given camera sensor mode.</p>
+ * <p><b>Possible values:</b></p>
+ * <ul>
+ * <li>{@link #SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED NOT_SUPPORTED}</li>
+ * <li>{@link #SENSOR_READOUT_TIMESTAMP_HARDWARE HARDWARE}</li>
+ * </ul>
+ *
+ * <p>This key is available on all devices.</p>
+ * @see #SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED
+ * @see #SENSOR_READOUT_TIMESTAMP_HARDWARE
+ * @hide
+ */
+ @PublicKey
+ @NonNull
+ public static final Key<Integer> SENSOR_READOUT_TIMESTAMP =
+ new Key<Integer>("android.sensor.readoutTimestamp", int.class);
+
+ /**
* <p>List of lens shading modes for {@link CaptureRequest#SHADING_MODE android.shading.mode} that are supported by this camera device.</p>
* <p>This list contains lens shading modes that can be set for the camera device.
* Camera devices that support the MANUAL_POST_PROCESSING capability will always
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index eb8c73aced39..c67a560b5885 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1658,6 +1658,28 @@ public abstract class CameraMetadata<TKey> {
public static final int SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN = 24;
//
+ // Enumeration values for CameraCharacteristics#SENSOR_READOUT_TIMESTAMP
+ //
+
+ /**
+ * <p>This camera device doesn't support readout timestamp and onReadoutStarted
+ * callback.</p>
+ * @see CameraCharacteristics#SENSOR_READOUT_TIMESTAMP
+ * @hide
+ */
+ public static final int SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED = 0;
+
+ /**
+ * <p>This camera device supports the onReadoutStarted callback as well as outputting
+ * readout timestamp for streams with TIMESTAMP_BASE_READOUT_SENSOR timestamp base. The
+ * readout timestamp is generated by the camera hardware and it has the same accuracy
+ * and timing characteristics of the start-of-exposure time.</p>
+ * @see CameraCharacteristics#SENSOR_READOUT_TIMESTAMP
+ * @hide
+ */
+ public static final int SENSOR_READOUT_TIMESTAMP_HARDWARE = 1;
+
+ //
// Enumeration values for CameraCharacteristics#LED_AVAILABLE_LEDS
//
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 9a9163c724ff..b9eba9c1d541 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -657,6 +657,21 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
}
@Override
+ public void onReadoutStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp, long frameNumber) {
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onReadoutStarted(
+ CameraCaptureSessionImpl.this, request, timestamp,
+ frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public void onCapturePartial(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureResult result) {
if ((callback != null) && (executor != null)) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 3cb0c93d8409..a6c79b3a289f 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2025,12 +2025,16 @@ public class CameraDeviceImpl extends CameraDevice
resultExtras.getLastCompletedReprocessFrameNumber();
final long lastCompletedZslFrameNumber =
resultExtras.getLastCompletedZslFrameNumber();
+ final boolean hasReadoutTimestamp = resultExtras.hasReadoutTimestamp();
+ final long readoutTimestamp = resultExtras.getReadoutTimestamp();
if (DEBUG) {
Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber
+ ": completedRegularFrameNumber " + lastCompletedRegularFrameNumber
+ ", completedReprocessFrameNUmber " + lastCompletedReprocessFrameNumber
- + ", completedZslFrameNumber " + lastCompletedZslFrameNumber);
+ + ", completedZslFrameNumber " + lastCompletedZslFrameNumber
+ + ", hasReadoutTimestamp " + hasReadoutTimestamp
+ + (hasReadoutTimestamp ? ", readoutTimestamp " + readoutTimestamp : "")) ;
}
final CaptureCallbackHolder holder;
@@ -2082,14 +2086,26 @@ public class CameraDeviceImpl extends CameraDevice
CameraDeviceImpl.this,
holder.getRequest(i),
timestamp - (subsequenceId - i) *
- NANO_PER_SECOND/fpsRange.getUpper(),
+ NANO_PER_SECOND / fpsRange.getUpper(),
frameNumber - (subsequenceId - i));
+ if (hasReadoutTimestamp) {
+ holder.getCallback().onReadoutStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ readoutTimestamp - (subsequenceId - i) *
+ NANO_PER_SECOND / fpsRange.getUpper(),
+ frameNumber - (subsequenceId - i));
+ }
}
} else {
holder.getCallback().onCaptureStarted(
- CameraDeviceImpl.this,
- holder.getRequest(resultExtras.getSubsequenceId()),
+ CameraDeviceImpl.this, request,
timestamp, frameNumber);
+ if (hasReadoutTimestamp) {
+ holder.getCallback().onReadoutStarted(
+ CameraDeviceImpl.this, request,
+ readoutTimestamp, frameNumber);
+ }
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CaptureCallback.java b/core/java/android/hardware/camera2/impl/CaptureCallback.java
index 6defe63b1766..b064e6a1f975 100644
--- a/core/java/android/hardware/camera2/impl/CaptureCallback.java
+++ b/core/java/android/hardware/camera2/impl/CaptureCallback.java
@@ -66,6 +66,13 @@ public abstract class CaptureCallback {
CaptureRequest request, long timestamp, long frameNumber);
/**
+ * This method is called when the camera device has started reading out the output
+ * image for the request, at the beginning of the sensor image readout.
+ */
+ public abstract void onReadoutStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp, long frameNumber);
+
+ /**
* This method is called when some results from an image capture are
* available.
*
diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index 5d9da73fd5c0..8bf94986a490 100644
--- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -33,6 +33,8 @@ public class CaptureResultExtras implements Parcelable {
private long lastCompletedRegularFrameNumber;
private long lastCompletedReprocessFrameNumber;
private long lastCompletedZslFrameNumber;
+ private boolean hasReadoutTimestamp;
+ private long readoutTimestamp;
public static final @android.annotation.NonNull Parcelable.Creator<CaptureResultExtras> CREATOR =
new Parcelable.Creator<CaptureResultExtras>() {
@@ -56,7 +58,8 @@ public class CaptureResultExtras implements Parcelable {
int partialResultCount, int errorStreamId,
String errorPhysicalCameraId, long lastCompletedRegularFrameNumber,
long lastCompletedReprocessFrameNumber,
- long lastCompletedZslFrameNumber) {
+ long lastCompletedZslFrameNumber, boolean hasReadoutTimestamp,
+ long readoutTimestamp) {
this.requestId = requestId;
this.subsequenceId = subsequenceId;
this.afTriggerId = afTriggerId;
@@ -68,6 +71,8 @@ public class CaptureResultExtras implements Parcelable {
this.lastCompletedRegularFrameNumber = lastCompletedRegularFrameNumber;
this.lastCompletedReprocessFrameNumber = lastCompletedReprocessFrameNumber;
this.lastCompletedZslFrameNumber = lastCompletedZslFrameNumber;
+ this.hasReadoutTimestamp = hasReadoutTimestamp;
+ this.readoutTimestamp = readoutTimestamp;
}
@Override
@@ -93,6 +98,10 @@ public class CaptureResultExtras implements Parcelable {
dest.writeLong(lastCompletedRegularFrameNumber);
dest.writeLong(lastCompletedReprocessFrameNumber);
dest.writeLong(lastCompletedZslFrameNumber);
+ dest.writeBoolean(hasReadoutTimestamp);
+ if (hasReadoutTimestamp) {
+ dest.writeLong(readoutTimestamp);
+ }
}
public void readFromParcel(Parcel in) {
@@ -110,6 +119,10 @@ public class CaptureResultExtras implements Parcelable {
lastCompletedRegularFrameNumber = in.readLong();
lastCompletedReprocessFrameNumber = in.readLong();
lastCompletedZslFrameNumber = in.readLong();
+ hasReadoutTimestamp = in.readBoolean();
+ if (hasReadoutTimestamp) {
+ readoutTimestamp = in.readLong();
+ }
}
public String getErrorPhysicalCameraId() {
@@ -155,4 +168,12 @@ public class CaptureResultExtras implements Parcelable {
public long getLastCompletedZslFrameNumber() {
return lastCompletedZslFrameNumber;
}
+
+ public boolean hasReadoutTimestamp() {
+ return hasReadoutTimestamp;
+ }
+
+ public long getReadoutTimestamp() {
+ return readoutTimestamp;
+ }
}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 4a2517763aae..9e8703779863 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -245,6 +245,26 @@ public final class OutputConfiguration implements Parcelable {
*/
public static final int TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED = 4;
+ /**
+ * Timestamp is the start of readout in the same time domain as TIMESTAMP_BASE_SENSOR.
+ *
+ * <p>The start of the camera sensor readout after exposure. For a rolling shutter camera
+ * sensor, the timestamp is typically equal to the start of exposure time +
+ * exposure time + certain fixed offset. The fixed offset could be due to camera sensor
+ * level crop. The benefit of using readout time is that when camera runs in a fixed
+ * frame rate, the timestamp intervals between frames are constant.</p>
+ *
+ * <p>This timestamp is in the same time domain as in TIMESTAMP_BASE_SENSOR, with the exception
+ * that one is start of exposure, and the other is start of readout.</p>
+ *
+ * <p>This timestamp base is supported only if {@link
+ * CameraCharacteristics#SENSOR_READOUT_TIMESTAMP} is
+ * {@link CameraMetadata#SENSOR_READOUT_TIMESTAMP_HARDWARE}.</p>
+ *
+ * @hide
+ */
+ public static final int TIMESTAMP_BASE_READOUT_SENSOR = 5;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"TIMESTAMP_BASE_"}, value =
@@ -252,7 +272,8 @@ public final class OutputConfiguration implements Parcelable {
TIMESTAMP_BASE_SENSOR,
TIMESTAMP_BASE_MONOTONIC,
TIMESTAMP_BASE_REALTIME,
- TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED})
+ TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED,
+ TIMESTAMP_BASE_READOUT_SENSOR})
public @interface TimestampBase {};
/** @hide */
@@ -974,7 +995,7 @@ public final class OutputConfiguration implements Parcelable {
public void setTimestampBase(@TimestampBase int timestampBase) {
// Verify that the value is in range
if (timestampBase < TIMESTAMP_BASE_DEFAULT ||
- timestampBase > TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED) {
+ timestampBase > TIMESTAMP_BASE_READOUT_SENSOR) {
throw new IllegalArgumentException("Not a valid timestamp base value " +
timestampBase);
}
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 7d8f2ff92200..8c71b363eb7b 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -89,7 +89,8 @@ public class AmbientDisplayConfiguration {
/** @hide */
public boolean pulseOnNotificationAvailable() {
- return ambientDisplayAvailable();
+ return mContext.getResources().getBoolean(R.bool.config_pulseOnNotificationsAvailable)
+ && ambientDisplayAvailable();
}
/** @hide */
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 74356ddecc76..e2f8592ad329 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -40,6 +40,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.Trace;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -996,7 +997,8 @@ public final class DisplayManagerGlobal {
@Override
public void onDisplayEvent(int displayId, @DisplayEvent int event) {
if (DEBUG) {
- Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
+ Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString(
+ event));
}
handleDisplayEvent(displayId, event);
}
@@ -1030,6 +1032,12 @@ public final class DisplayManagerGlobal {
@Override
public void handleMessage(Message msg) {
+ if (DEBUG) {
+ Trace.beginSection(
+ "DisplayListenerDelegate(" + eventToString(msg.what)
+ + ", display=" + msg.arg1
+ + ", listener=" + mListener.getClass() + ")");
+ }
switch (msg.what) {
case EVENT_DISPLAY_ADDED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
@@ -1056,6 +1064,9 @@ public final class DisplayManagerGlobal {
}
break;
}
+ if (DEBUG) {
+ Trace.endSection();
+ }
}
}
@@ -1162,4 +1173,18 @@ public final class DisplayManagerGlobal {
updateCallbackIfNeededLocked();
}
}
+
+ private static String eventToString(@DisplayEvent int event) {
+ switch (event) {
+ case EVENT_DISPLAY_ADDED:
+ return "ADDED";
+ case EVENT_DISPLAY_CHANGED:
+ return "CHANGED";
+ case EVENT_DISPLAY_REMOVED:
+ return "REMOVED";
+ case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
+ return "BRIGHTNESS_CHANGED";
+ }
+ return "UNKNOWN";
+ }
}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 31f3b6aef251..7092e43596ec 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1363,19 +1363,31 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
// Consolidate positional feedback to reduce noise during authentication.
case FACE_ACQUIRED_NOT_DETECTED:
+ return context.getString(R.string.face_acquired_not_detected);
case FACE_ACQUIRED_TOO_CLOSE:
+ return context.getString(R.string.face_acquired_too_close);
case FACE_ACQUIRED_TOO_FAR:
+ return context.getString(R.string.face_acquired_too_far);
case FACE_ACQUIRED_TOO_HIGH:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_low);
case FACE_ACQUIRED_TOO_LOW:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_high);
case FACE_ACQUIRED_TOO_RIGHT:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_left);
case FACE_ACQUIRED_TOO_LEFT:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_right);
case FACE_ACQUIRED_POOR_GAZE:
+ return context.getString(R.string.face_acquired_poor_gaze);
case FACE_ACQUIRED_PAN_TOO_EXTREME:
+ return context.getString(R.string.face_acquired_pan_too_extreme);
case FACE_ACQUIRED_TILT_TOO_EXTREME:
+ return context.getString(R.string.face_acquired_tilt_too_extreme);
case FACE_ACQUIRED_ROLL_TOO_EXTREME:
- return context.getString(R.string.face_acquired_poor_gaze);
-
- // Provide more detailed feedback for other soft errors.
+ return context.getString(R.string.face_acquired_roll_too_extreme);
case FACE_ACQUIRED_INSUFFICIENT:
return context.getString(R.string.face_acquired_insufficient);
case FACE_ACQUIRED_TOO_BRIGHT:
@@ -1394,6 +1406,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
return context.getString(R.string.face_acquired_obscured);
case FACE_ACQUIRED_SENSOR_DIRTY:
return context.getString(R.string.face_acquired_sensor_dirty);
+ case FACE_ACQUIRED_DARK_GLASSES_DETECTED:
+ return context.getString(R.string.face_acquired_dark_glasses_detected);
+ case FACE_ACQUIRED_MOUTH_COVERING_DETECTED:
+ return context.getString(R.string.face_acquired_mouth_covering_detected);
// Find and return the appropriate vendor-specific message.
case FACE_ACQUIRED_VENDOR: {
@@ -1459,11 +1475,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
case FACE_ACQUIRED_ROLL_TOO_EXTREME:
return context.getString(R.string.face_acquired_roll_too_extreme);
case FACE_ACQUIRED_FACE_OBSCURED:
- case FACE_ACQUIRED_DARK_GLASSES_DETECTED:
- case FACE_ACQUIRED_MOUTH_COVERING_DETECTED:
return context.getString(R.string.face_acquired_obscured);
case FACE_ACQUIRED_SENSOR_DIRTY:
return context.getString(R.string.face_acquired_sensor_dirty);
+ case FACE_ACQUIRED_DARK_GLASSES_DETECTED:
+ return context.getString(R.string.face_acquired_dark_glasses_detected);
+ case FACE_ACQUIRED_MOUTH_COVERING_DETECTED:
+ return context.getString(R.string.face_acquired_mouth_covering_detected);
case FACE_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
R.array.face_acquired_vendor);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 2da12e6c5c9d..c9a096cb1a1f 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -38,6 +38,8 @@ import android.view.VerifiedInputEvent;
/** @hide */
interface IInputManager {
+ // Gets the current VelocityTracker strategy
+ String getVelocityTrackerStrategy();
// Gets input device information.
InputDevice getInputDevice(int deviceId);
int[] getInputDeviceIds();
diff --git a/core/java/android/hardware/input/InputDeviceIdentifier.java b/core/java/android/hardware/input/InputDeviceIdentifier.java
index a5b9a2a4da76..3fd0e3154199 100644
--- a/core/java/android/hardware/input/InputDeviceIdentifier.java
+++ b/core/java/android/hardware/input/InputDeviceIdentifier.java
@@ -88,6 +88,12 @@ public final class InputDeviceIdentifier implements Parcelable {
return Objects.hash(mDescriptor, mVendorId, mProductId);
}
+ @Override
+ public String toString() {
+ return "InputDeviceIdentifier: vendorId: " + mVendorId + ", productId: " + mProductId
+ + ", descriptor: " + mDescriptor;
+ }
+
public static final @android.annotation.NonNull Parcelable.Creator<InputDeviceIdentifier> CREATOR =
new Parcelable.Creator<InputDeviceIdentifier>() {
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index d17a9523ab37..6ad1c7274ee5 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -36,7 +36,6 @@ import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
import android.hardware.lights.LightsRequest;
import android.os.Binder;
-import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.CombinedVibration;
import android.os.Handler;
@@ -68,7 +67,6 @@ import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
-import com.android.internal.util.ArrayUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -81,19 +79,13 @@ import java.util.List;
@SystemService(Context.INPUT_SERVICE)
public final class InputManager {
private static final String TAG = "InputManager";
- private static final boolean DEBUG = false;
+ // To enable these logs, run: 'adb shell setprop log.tag.InputManager DEBUG' (requires restart)
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int MSG_DEVICE_ADDED = 1;
private static final int MSG_DEVICE_REMOVED = 2;
private static final int MSG_DEVICE_CHANGED = 3;
- /** @hide */
- public static final int[] BLOCK_UNTRUSTED_TOUCHES_MODES = {
- BlockUntrustedTouchesMode.DISABLED,
- BlockUntrustedTouchesMode.PERMISSIVE,
- BlockUntrustedTouchesMode.BLOCK
- };
-
private static InputManager sInstance;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -200,14 +192,6 @@ public final class InputManager {
public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f;
/**
- * Default mode of the block untrusted touches mode feature.
- * @hide
- */
- @BlockUntrustedTouchesMode
- public static final int DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE =
- BlockUntrustedTouchesMode.BLOCK;
-
- /**
* Prevent touches from being consumed by apps if these touches passed through a non-trusted
* window from a different UID and are considered unsafe.
*
@@ -273,8 +257,15 @@ public final class InputManager {
*/
public static final int SWITCH_STATE_ON = 1;
+ private static String sVelocityTrackerStrategy;
+
private InputManager(IInputManager im) {
mIm = im;
+ try {
+ sVelocityTrackerStrategy = mIm.getVelocityTrackerStrategy();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not get VelocityTracker strategy: " + ex);
+ }
}
/**
@@ -327,10 +318,19 @@ public final class InputManager {
}
/**
+ * Get the current VelocityTracker strategy. Only works when the system has fully booted up.
+ * @hide
+ */
+ public String getVelocityTrackerStrategy() {
+ return sVelocityTrackerStrategy;
+ }
+
+ /**
* Gets information about the input device with the specified id.
* @param id The device id.
* @return The input device or null if not found.
*/
+ @Nullable
public InputDevice getInputDevice(int id) {
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();
@@ -999,50 +999,6 @@ public final class InputManager {
}
/**
- * Returns the current mode of the block untrusted touches feature, one of:
- * <ul>
- * <li>{@link BlockUntrustedTouchesMode#DISABLED}
- * <li>{@link BlockUntrustedTouchesMode#PERMISSIVE}
- * <li>{@link BlockUntrustedTouchesMode#BLOCK}
- * </ul>
- *
- * @hide
- */
- @TestApi
- @BlockUntrustedTouchesMode
- public int getBlockUntrustedTouchesMode(@NonNull Context context) {
- int mode = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE, DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE);
- if (!ArrayUtils.contains(BLOCK_UNTRUSTED_TOUCHES_MODES, mode)) {
- Log.w(TAG, "Unknown block untrusted touches feature mode " + mode + ", using "
- + "default " + DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE);
- return DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE;
- }
- return mode;
- }
-
- /**
- * Sets the mode of the block untrusted touches feature to one of:
- * <ul>
- * <li>{@link BlockUntrustedTouchesMode#DISABLED}
- * <li>{@link BlockUntrustedTouchesMode#PERMISSIVE}
- * <li>{@link BlockUntrustedTouchesMode#BLOCK}
- * </ul>
- *
- * @hide
- */
- @TestApi
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public void setBlockUntrustedTouchesMode(@NonNull Context context,
- @BlockUntrustedTouchesMode int mode) {
- if (!ArrayUtils.contains(BLOCK_UNTRUSTED_TOUCHES_MODES, mode)) {
- throw new IllegalArgumentException("Invalid feature mode " + mode);
- }
- Settings.Global.putInt(context.getContentResolver(),
- Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE, mode);
- }
-
- /**
* Queries the framework about whether any physical keys exist on any currently attached input
* devices that are capable of producing the given array of key codes.
*
@@ -1410,6 +1366,7 @@ public final class InputManager {
* </p>
* @hide
*/
+ @TestApi
public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
try {
mIm.addUniqueIdAssociation(inputPort, displayUniqueId);
@@ -1426,6 +1383,7 @@ public final class InputManager {
* </p>
* @hide
*/
+ @TestApi
public void removeUniqueIdAssociation(@NonNull String inputPort) {
try {
mIm.removeUniqueIdAssociation(inputPort);
@@ -1454,11 +1412,8 @@ public final class InputManager {
}
mInputDevices = new SparseArray<InputDevice>();
- // TODO(b/223905476): remove when the rootcause is fixed.
- if (ids != null) {
- for (int i = 0; i < ids.length; i++) {
- mInputDevices.put(ids[i], null);
- }
+ for (int i = 0; i < ids.length; i++) {
+ mInputDevices.put(ids[i], null);
}
}
}
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index 5bdbae39b5dd..52c15519907a 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -21,8 +21,6 @@ import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Locale;
-
/**
* Describes a keyboard layout.
*
@@ -157,9 +155,12 @@ public final class KeyboardLayout implements Parcelable,
@Override
public String toString() {
- if (mCollection.isEmpty()) {
- return mLabel;
- }
- return mLabel + " - " + mCollection;
+ String collectionString = mCollection.isEmpty() ? "" : " - " + mCollection;
+ return "KeyboardLayout " + mLabel + collectionString
+ + ", descriptor: " + mDescriptor
+ + ", priority: " + mPriority
+ + ", locales: " + mLocales.toString()
+ + ", vendorId: " + mVendorId
+ + ", productId: " + mProductId;
}
}
diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS
index c390b33fa174..4c20c4dc9d35 100644
--- a/core/java/android/hardware/input/OWNERS
+++ b/core/java/android/hardware/input/OWNERS
@@ -1,3 +1 @@
-# Bug component: 136048
-
-include /services/core/java/com/android/server/input/OWNERS
+include /INPUT_OWNERS
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index d525753a1874..6300a12c3137 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -279,6 +279,7 @@ public final class ProgramSelector implements Parcelable {
mPrimaryId = Objects.requireNonNull(primaryId);
mSecondaryIds = secondaryIds;
mVendorIds = vendorIds;
+ Arrays.sort(mSecondaryIds);
}
/**
@@ -512,10 +513,22 @@ public final class ProgramSelector implements Parcelable {
return mPrimaryId.equals(other.getPrimaryId());
}
+ /** @hide */
+ public boolean strictEquals(@Nullable Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof ProgramSelector)) return false;
+ ProgramSelector other = (ProgramSelector) obj;
+ // vendorIds are ignored for equality
+ // programType can be inferred from primaryId, thus not checked
+ return mPrimaryId.equals(other.getPrimaryId())
+ && Arrays.equals(mSecondaryIds, other.mSecondaryIds);
+ }
+
private ProgramSelector(Parcel in) {
mProgramType = in.readInt();
mPrimaryId = in.readTypedObject(Identifier.CREATOR);
mSecondaryIds = in.createTypedArray(Identifier.CREATOR);
+ Arrays.sort(mSecondaryIds);
if (Stream.of(mSecondaryIds).anyMatch(id -> id == null)) {
throw new IllegalArgumentException("secondaryIds list must not contain nulls");
}
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 4cc001a40146..8180caa1557b 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -1690,7 +1690,7 @@ public class RadioManager {
if (!(obj instanceof ProgramInfo)) return false;
ProgramInfo other = (ProgramInfo) obj;
- if (!Objects.equals(mSelector, other.mSelector)) return false;
+ if (!mSelector.strictEquals(other.mSelector)) return false;
if (!Objects.equals(mLogicallyTunedTo, other.mLogicallyTunedTo)) return false;
if (!Objects.equals(mPhysicallyTunedTo, other.mPhysicallyTunedTo)) return false;
if (!Objects.equals(mRelatedContent, other.mRelatedContent)) return false;
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 3a6d5087c260..694d6d8c23c0 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -40,11 +40,11 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -151,7 +151,7 @@ public class KeyphraseEnrollmentInfo {
return;
}
- List<String> parseErrors = new LinkedList<>();
+ List<String> parseErrors = new ArrayList<>();
mKeyphrasePackageMap = new HashMap<>();
for (ResolveInfo ri : ris) {
try {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 334a659d7f23..04f39a0e986a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -147,6 +147,7 @@ import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.util.RingBuffer;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInputContext;
@@ -351,6 +352,7 @@ public class InputMethodService extends AbstractInputMethodService {
private ImeOnBackInvokedDispatcher mImeDispatcher;
private Boolean mBackCallbackRegistered = false;
private final OnBackInvokedCallback mCompatBackCallback = this::compatHandleBack;
+ private Runnable mImeSurfaceRemoverRunnable;
/**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and
@@ -597,7 +599,6 @@ public class InputMethodService extends AbstractInputMethodService {
private @NonNull OptionalInt mHandwritingRequestId = OptionalInt.empty();
private InputEventReceiver mHandwritingEventReceiver;
private Handler mHandler;
- private boolean mImeSurfaceScheduledForRemoval;
private ImsConfigurationTracker mConfigTracker = new ImsConfigurationTracker();
private boolean mDestroyed;
private boolean mOnPreparedStylusHwCalled;
@@ -1078,7 +1079,7 @@ public class InputMethodService extends AbstractInputMethodService {
private void scheduleImeSurfaceRemoval() {
if (mShowInputRequested || mWindowVisible || mWindow == null
- || mImeSurfaceScheduledForRemoval) {
+ || mImeSurfaceRemoverRunnable != null) {
return;
}
if (mHandler == null) {
@@ -1092,24 +1093,26 @@ public class InputMethodService extends AbstractInputMethodService {
// view issues is resolved in RecyclerView.
removeImeSurface();
} else {
- mImeSurfaceScheduledForRemoval = true;
- mHandler.postDelayed(() -> removeImeSurface(), TIMEOUT_SURFACE_REMOVAL_MILLIS);
+ mImeSurfaceRemoverRunnable = () -> {
+ removeImeSurface();
+ };
+ mHandler.postDelayed(mImeSurfaceRemoverRunnable, TIMEOUT_SURFACE_REMOVAL_MILLIS);
}
}
private void removeImeSurface() {
+ cancelImeSurfaceRemoval();
// hiding a window removes its surface.
if (mWindow != null) {
mWindow.hide();
}
- mImeSurfaceScheduledForRemoval = false;
}
private void cancelImeSurfaceRemoval() {
- if (mHandler != null && mImeSurfaceScheduledForRemoval) {
- mHandler.removeCallbacksAndMessages(null /* token */);
- mImeSurfaceScheduledForRemoval = false;
+ if (mHandler != null && mImeSurfaceRemoverRunnable != null) {
+ mHandler.removeCallbacks(mImeSurfaceRemoverRunnable);
}
+ mImeSurfaceRemoverRunnable = null;
}
private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
@@ -2961,9 +2964,13 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public void requestHideSelf(int flags) {
+ requestHideSelf(flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME);
+ }
+
+ private void requestHideSelf(int flags, @SoftInputShowHideReason int reason) {
ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
null /* icProto */);
- mPrivOps.hideMySoftInput(flags);
+ mPrivOps.hideMySoftInput(flags, reason);
}
/**
@@ -2984,7 +2991,9 @@ public class InputMethodService extends AbstractInputMethodService {
if (mShowInputRequested) {
// If the soft input area is shown, back closes it and we
// consume the back key.
- if (doIt) requestHideSelf(0);
+ if (doIt) {
+ requestHideSelf(0 /* flags */, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY);
+ }
return true;
} else if (mDecorViewVisible) {
if (mCandidatesVisibility == View.VISIBLE) {
@@ -3135,7 +3144,8 @@ public class InputMethodService extends AbstractInputMethodService {
private void onToggleSoftInput(int showFlags, int hideFlags) {
if (DEBUG) Log.v(TAG, "toggleSoftInput()");
if (isInputViewShown()) {
- requestHideSelf(hideFlags);
+ requestHideSelf(
+ hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
} else {
requestShowSelf(showFlags);
}
@@ -3570,7 +3580,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public void onExtractingInputChanged(EditorInfo ei) {
if (ei.inputType == InputType.TYPE_NULL) {
- requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
+ requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED);
}
}
@@ -3787,7 +3798,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (mInputEditorInfo != null) {
p.println(" mInputEditorInfo:");
- mInputEditorInfo.dump(p, " ");
+ mInputEditorInfo.dump(p, " ", false /* dumpExtras */);
} else {
p.println(" mInputEditorInfo: null");
}
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index e1ccc4fb740b..170df71385bb 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -46,6 +46,5 @@ interface INfcTag
int getMaxTransceiveLength(int technology);
boolean getExtendedLengthApdusSupported();
- void setTagUpToDate(long cookie);
boolean isTagUpToDate(long cookie);
}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 731d1ba78299..500038f14d9d 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -34,7 +34,6 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.SystemClock;
import java.io.IOException;
import java.util.Arrays;
@@ -119,17 +118,17 @@ public final class Tag implements Parcelable {
final String[] mTechStringList;
final Bundle[] mTechExtras;
final int mServiceHandle; // for use by NFC service, 0 indicates a mock
+ final long mCookie; // for accessibility checking
final INfcTag mTagService; // interface to NFC service, will be null if mock tag
int mConnectedTechnology;
- long mCookie;
/**
* Hidden constructor to be used by NFC service and internal classes.
* @hide
*/
public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle,
- INfcTag tagService) {
+ long cookie, INfcTag tagService) {
if (techList == null) {
throw new IllegalArgumentException("rawTargets cannot be null");
}
@@ -139,20 +138,13 @@ public final class Tag implements Parcelable {
// Ensure mTechExtras is as long as mTechList
mTechExtras = Arrays.copyOf(techListExtras, techList.length);
mServiceHandle = serviceHandle;
+ mCookie = cookie;
mTagService = tagService;
-
mConnectedTechnology = -1;
- mCookie = SystemClock.elapsedRealtime();
if (tagService == null) {
return;
}
-
- try {
- tagService.setTagUpToDate(mCookie);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
}
/**
@@ -165,9 +157,10 @@ public final class Tag implements Parcelable {
* @return freshly constructed tag
* @hide
*/
- public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) {
+ public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras,
+ long cookie) {
// set serviceHandle to 0 and tagService to null to indicate mock tag
- return new Tag(id, techList, techListExtras, 0, null);
+ return new Tag(id, techList, techListExtras, 0, cookie, null);
}
private String[] generateTechStringList(int[] techList) {
@@ -445,6 +438,7 @@ public final class Tag implements Parcelable {
dest.writeIntArray(mTechList);
dest.writeTypedArray(mTechExtras, 0);
dest.writeInt(mServiceHandle);
+ dest.writeLong(mCookie);
dest.writeInt(isMock);
if (isMock == 0) {
dest.writeStrongBinder(mTagService.asBinder());
@@ -463,6 +457,7 @@ public final class Tag implements Parcelable {
in.readIntArray(techList);
Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR);
int serviceHandle = in.readInt();
+ long cookie = in.readLong();
int isMock = in.readInt();
if (isMock == 0) {
tagService = INfcTag.Stub.asInterface(in.readStrongBinder());
@@ -471,7 +466,7 @@ public final class Tag implements Parcelable {
tagService = null;
}
- return new Tag(id, techList, techExtras, serviceHandle, tagService);
+ return new Tag(id, techList, techExtras, serviceHandle, cookie, tagService);
}
@Override
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0b956f8bf9e0..dbd602f27c11 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1167,6 +1167,11 @@ public class Build {
* Tiramisu.
*/
public static final int TIRAMISU = 33;
+
+ /**
+ * Upside Down Cake.
+ */
+ public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index cb7e6f71a8fd..43a6be5df202 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -107,20 +107,41 @@ public class GraphicsEnvironment {
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2;
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_OFF = 3;
+ // System properties related to ANGLE and legacy GLES graphics drivers.
+ private static final String PROPERTY_EGL_SYSTEM_DRIVER = "ro.hardware.egl";
+ // TODO (b/224558229): Properly add this to the list of system properties for a device:
+ private static final String PROPERTY_EGL_LEGACY_DRIVER = "ro.hardware.egl_legacy";
+
// Values for ANGLE_GL_DRIVER_ALL_ANGLE
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_ON = 1;
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_OFF = 0;
+ private static final int ANGLE_GL_DRIVER_ALL_LEGACY = -1;
// Values for ANGLE_GL_DRIVER_SELECTION_VALUES
private static final String ANGLE_GL_DRIVER_CHOICE_DEFAULT = "default";
private static final String ANGLE_GL_DRIVER_CHOICE_ANGLE = "angle";
+ private static final String ANGLE_GL_DRIVER_CHOICE_LEGACY = "legacy";
+ // The following value is a deprecated choice for "legacy"
private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native";
+ // Values returned by getDriverForPackage() and getDefaultDriverToUse() (avoid returning
+ // strings for performance reasons)
+ private static final int ANGLE_GL_DRIVER_TO_USE_LEGACY = 0;
+ private static final int ANGLE_GL_DRIVER_TO_USE_ANGLE = 1;
+
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
private GameManager mGameManager;
+ private boolean mAngleIsSystemDriver = false;
+ private boolean mNoLegacyDriver = false;
+ // When ANGLE is the system driver, this is the name of the legacy driver.
+ //
+ // TODO (b/224558229): This is temporarily set to a value that works for testing, until
+ // PROPERTY_EGL_LEGACY_DRIVER has been properly plumbed and this becomes broadly available.
+ private String mEglLegacyDriver = "mali";
+
private int mAngleOptInIndex = -1;
/**
@@ -138,6 +159,25 @@ public class GraphicsEnvironment {
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ // Determine if ANGLE is the system driver, as this will determine other logic
+ final String eglSystemDriver = SystemProperties.get(PROPERTY_EGL_SYSTEM_DRIVER);
+ Log.v(TAG, "GLES system driver is '" + eglSystemDriver + "'");
+ mAngleIsSystemDriver = eglSystemDriver.equals(ANGLE_DRIVER_NAME);
+ if (mAngleIsSystemDriver) {
+ // Lookup the legacy driver, to send down to the EGL loader
+ final String eglLegacyDriver = SystemProperties.get(PROPERTY_EGL_LEGACY_DRIVER);
+ if (eglLegacyDriver.isEmpty()) {
+ mNoLegacyDriver = true;
+ // TBD/TODO: Do we need this?:
+ mEglLegacyDriver = eglSystemDriver;
+ }
+ } else {
+ // TBD/TODO: Do we need this?:
+ mEglLegacyDriver = eglSystemDriver;
+ }
+ Log.v(TAG, "Legacy GLES driver is '" + mEglLegacyDriver + "'");
+
+ // Setup ANGLE and pass down ANGLE details to the C++ code
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
boolean useAngle = false;
if (setupAngle(context, coreSettings, pm, packageName)) {
@@ -145,6 +185,10 @@ public class GraphicsEnvironment {
useAngle = true;
setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
0, packageName, getVulkanVersion(pm));
+ } else if (mNoLegacyDriver) {
+ // TBD: The following should never happen--does it?
+ Log.e(TAG, "Unexpected problem with the ANGLE for use with: '" + packageName + "'");
+ useAngle = true;
}
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -188,28 +232,15 @@ public class GraphicsEnvironment {
/**
* Query to determine if ANGLE should be used
*/
- private boolean shouldUseAngle(Context context, Bundle coreSettings,
- String packageName) {
+ private boolean shouldUseAngle(Context context, Bundle coreSettings, String packageName) {
if (TextUtils.isEmpty(packageName)) {
- Log.v(TAG, "No package name specified, ANGLE should not be used");
- return false;
+ Log.v(TAG, "No package name specified; use the system driver");
+ return mAngleIsSystemDriver ? true : false;
}
- final String devOptIn = getDriverForPackage(context, coreSettings, packageName);
- Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
- + "set to: '" + devOptIn + "'");
-
- // We only want to use ANGLE if the developer has explicitly chosen something other than
- // default driver.
- final boolean forceAngle = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
- final boolean forceNative = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE);
- if (forceAngle || forceNative) {
- Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
- }
-
- final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
-
- return !forceNative && (forceAngle || gameModeEnabledAngle);
+ final int driverToUse = getDriverForPackage(context, coreSettings, packageName);
+ boolean yesOrNo = driverToUse == ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ return yesOrNo;
}
private int getVulkanVersion(PackageManager pm) {
@@ -417,34 +448,69 @@ public class GraphicsEnvironment {
return ai;
}
- private String getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ /**
+ * Return the appropriate "default" driver, unless overridden by isAngleEnabledByGameMode().
+ */
+ private int getDefaultDriverToUse(Context context, String packageName) {
+ if (mAngleIsSystemDriver || isAngleEnabledByGameMode(context, packageName)) {
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ } else {
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+ }
+ }
+
+ /*
+ * Determine which GLES "driver" should be used for the package, taking into account the
+ * following factors (in priority order):
+ *
+ * 1) The semi-global switch (i.e. Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE; which is set by
+ * the "angle_gl_driver_all_angle" setting; which forces a driver for all processes that
+ * start after the Java run time is up), if it forces a choice; otherwise ...
+ * 2) The per-application switch (i.e. Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS and
+ * Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES; which corresponds to the
+ * “angle_gl_driver_selection_pkgs” and “angle_gl_driver_selection_values” settings); if it
+ * forces a choice; otherwise ...
+ * 3) Use ANGLE if isAngleEnabledByGameMode() returns true; otherwise ...
+ * 4) The global switch (i.e. use the system driver, whether ANGLE or legacy;
+ * a.k.a. mAngleIsSystemDriver, which is set by the device’s “ro.hardware.egl” property)
+ *
+ * Factors 1 and 2 are decided by this method. Factors 3 and 4 are decided by
+ * getDefaultDriverToUse().
+ */
+ private int getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ // Check the semi-global switch (i.e. once system has booted enough) for whether ANGLE
+ // should be forced on or off for "all appplications"
final int allUseAngle;
if (bundle != null) {
- allUseAngle =
- bundle.getInt(Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE);
+ allUseAngle = bundle.getInt(Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE);
} else {
ContentResolver contentResolver = context.getContentResolver();
allUseAngle = Settings.Global.getInt(contentResolver,
- Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE,
- ANGLE_GL_DRIVER_ALL_ANGLE_OFF);
+ Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE, ANGLE_GL_DRIVER_ALL_ANGLE_OFF);
}
if (allUseAngle == ANGLE_GL_DRIVER_ALL_ANGLE_ON) {
Log.v(TAG, "Turn on ANGLE for all applications.");
- return ANGLE_GL_DRIVER_CHOICE_ANGLE;
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ }
+ if (allUseAngle == ANGLE_GL_DRIVER_ALL_LEGACY) {
+ Log.v(TAG, "Disable ANGLE for all applications.");
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
}
// Make sure we have a good package name
if (TextUtils.isEmpty(packageName)) {
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ return getDefaultDriverToUse(context, packageName);
}
+ // Get the per-application settings lists
final ContentResolver contentResolver = context.getContentResolver();
- final List<String> optInPackages =
- getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
- final List<String> optInValues =
- getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
+ final List<String> optInPackages = getGlobalSettingsString(
+ contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
+ final List<String> optInValues = getGlobalSettingsString(
+ contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
+ Log.v(TAG, "Currently set values for:");
+ Log.v(TAG, " angle_gl_driver_selection_pkgs = " + optInPackages);
+ Log.v(TAG, " angle_gl_driver_selection_values =" + optInValues);
// Make sure we have good settings to use
if (optInPackages.size() != optInValues.size()) {
@@ -454,17 +520,40 @@ public class GraphicsEnvironment {
+ optInPackages.size() + ", "
+ "number of values: "
+ optInValues.size());
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ return getDefaultDriverToUse(context, packageName);
}
+ // See if this application is listed in the per-application settings lists
final int pkgIndex = getPackageIndex(packageName, optInPackages);
if (pkgIndex < 0) {
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ // The application is NOT listed in the per-application settings lists; and so use the
+ // system driver (i.e. either ANGLE or the Legacy driver)
+ Log.v(TAG, "getDriverForPackage(): No per-application setting");
+ return getDefaultDriverToUse(context, packageName);
}
mAngleOptInIndex = pkgIndex;
- return optInValues.get(pkgIndex);
+ Log.v(TAG,
+ "getDriverForPackage(): using per-application switch: "
+ + optInValues.get(pkgIndex));
+ // The application IS listed in the per-application settings lists; and so use the
+ // setting--choosing the current system driver if the setting is "default" (i.e. either
+ // ANGLE or the Legacy driver)
+ String rtnValue = optInValues.get(pkgIndex);
+ Log.v(TAG,
+ "ANGLE Developer option for '" + packageName + "' "
+ + "set to: '" + rtnValue + "'");
+ if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ } else if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)
+ || rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_LEGACY)) {
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+ } else {
+ // The user either chose default or an invalid value; go with the default driver or what
+ // the game dashboard indicates
+ return getDefaultDriverToUse(context, packageName);
+ }
}
/**
@@ -514,7 +603,13 @@ public class GraphicsEnvironment {
}
/**
- * Pass ANGLE details down to trigger enable logic
+ * Determine whether ANGLE should be used, set it up if so, and pass ANGLE details down to
+ * the C++ GraphicsEnv class.
+ *
+ * If ANGLE will be used, GraphicsEnv::setAngleInfo() will be called to enable ANGLE to be
+ * properly used. Otherwise, GraphicsEnv::setLegacyDriverInfo() will be called to
+ * enable the legacy GLES driver (e.g. when ANGLE is the system driver) to be identified and
+ * used.
*
* @param context
* @param bundle
@@ -527,6 +622,7 @@ public class GraphicsEnvironment {
String packageName) {
if (!shouldUseAngle(context, bundle, packageName)) {
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
@@ -541,6 +637,7 @@ public class GraphicsEnvironment {
angleInfo = pm.getApplicationInfo(anglePkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
}
@@ -550,16 +647,18 @@ public class GraphicsEnvironment {
anglePkgName = getAnglePackageName(pm);
if (TextUtils.isEmpty(anglePkgName)) {
Log.w(TAG, "Failed to find ANGLE package.");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
- Log.i(TAG, "ANGLE package enabled: " + anglePkgName);
+ Log.v(TAG, "ANGLE package enabled: " + anglePkgName);
try {
// Production ANGLE libraries must be pre-installed as a system app
angleInfo = pm.getApplicationInfo(anglePkgName,
PackageManager.MATCH_SYSTEM_ONLY);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
}
@@ -573,21 +672,15 @@ public class GraphicsEnvironment {
+ "!/lib/"
+ abi;
- if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
+ if (DEBUG) {
+ Log.v(TAG, "ANGLE package libs: " + paths);
+ }
- // 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;
+ // If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
+ // and features to use.
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);
+ setAngleInfo(
+ paths, packageName, mAngleIsSystemDriver, ANGLE_GL_DRIVER_CHOICE_ANGLE, features);
return true;
}
@@ -876,8 +969,10 @@ public class GraphicsEnvironment {
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
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);
+ private static native void setAngleInfo(String path, String appPackage,
+ boolean angleIsSystemDriver, String devOptIn, String[] features);
+ private static native void setLegacyDriverInfo(
+ String appPackage, boolean angleIsSystemDriver, String legacyDriverName);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 9e47a708162d..90e4b17250d8 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -311,9 +311,11 @@ public interface IBinder {
public void binderDied();
/**
- * @hide
+ * Interface for receiving a callback when the process hosting an IBinder
+ * has gone away.
+ * @param who The IBinder that has become invalid
*/
- default void binderDied(IBinder who) {
+ default void binderDied(@NonNull IBinder who) {
binderDied();
}
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3cde0319efd3..e5de3e157c88 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -131,4 +131,5 @@ interface IUserManager {
String getUserName();
long getUserStartRealtime();
long getUserUnlockRealtime();
+ boolean setUserEphemeral(int userId, boolean enableEphemeral);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index e06e7326a860..14082f3388a0 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -213,12 +213,6 @@ public class Process {
public static final int SE_UID = 1068;
/**
- * Defines the UID/GID for the iorapd.
- * @hide
- */
- public static final int IORAPD_UID = 1071;
-
- /**
* Defines the UID/GID for the NetworkStack app.
* @hide
*/
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index ba5ed4360cd7..e321a660e8e0 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -276,6 +276,8 @@ public final class ServiceManager {
* @return {@code null} only if there are permission problems or fatal errors.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Nullable
public static IBinder waitForService(@NonNull String name) {
return Binder.allowBlocking(waitForServiceNative(name));
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index ac2156e9e46e..4965057a7fdb 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -140,7 +140,7 @@ public final class Trace {
String trackName, String name, int cookie);
@FastNative
private static native void nativeAsyncTraceForTrackEnd(long tag,
- String trackName, String name, int cookie);
+ String trackName, int cookie);
@FastNative
private static native void nativeInstant(long tag, String name);
@FastNative
@@ -281,8 +281,10 @@ public final class Trace {
/**
* Writes a trace message to indicate that a given section of code has
* begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same
- * tag. This function operates exactly like {@link #asyncTraceBegin(long, String, int)},
+ * track name and cookie.
+ * This function operates exactly like {@link #asyncTraceBegin(long, String, int)},
* except with the inclusion of a track name argument for where this method should appear.
+ * The cookie must be unique on the trackName level, not the methodName level
*
* @param traceTag The trace tag.
* @param trackName The track where the event should appear in the trace.
@@ -302,19 +304,31 @@ public final class Trace {
* Writes a trace message to indicate that the current method has ended.
* Must be called exactly once for each call to
* {@link #asyncTraceForTrackBegin(long, String, String, int)}
- * using the same tag, track name, name and cookie.
+ * using the same tag, track name, and cookie.
*
* @param traceTag The trace tag.
* @param trackName The track where the event should appear in the trace.
- * @param methodName The method name to appear in the trace.
* @param cookie Unique identifier for distinguishing simultaneous events
*
* @hide
*/
public static void asyncTraceForTrackEnd(long traceTag,
+ @NonNull String trackName, int cookie) {
+ if (isTagEnabled(traceTag)) {
+ nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie);
+ }
+ }
+
+ /**
+ * @deprecated use asyncTraceForTrackEnd without methodName argument
+ *
+ * @hide
+ */
+ @Deprecated
+ public static void asyncTraceForTrackEnd(long traceTag,
@NonNull String trackName, @NonNull String methodName, int cookie) {
if (isTagEnabled(traceTag)) {
- nativeAsyncTraceForTrackEnd(traceTag, trackName, methodName, cookie);
+ nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie);
}
}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 3d5abb3b8a2f..19706cbbe48d 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -404,7 +404,12 @@ public final class UserHandle implements Parcelable {
return getUid(userId, Process.SHARED_USER_GID);
}
- /** @hide */
+ /**
+ * Returns the gid shared between all users with the app that this uid represents, or -1 if the
+ * uid is invalid.
+ * @hide
+ */
+ @SystemApi
public static int getSharedAppGid(int uid) {
return getSharedAppGid(getUserId(uid), getAppId(uid));
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0ffdfc6cbcb1..8d3509c451a4 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -90,6 +90,7 @@ import java.util.Set;
public class UserManager {
private static final String TAG = "UserManager";
+
@UnsupportedAppUsage
private final IUserManager mService;
/** Holding the Application context (not constructor param context). */
@@ -1569,6 +1570,27 @@ public class UserManager {
@Retention(RetentionPolicy.SOURCE)
public @interface UserRestrictionKey {}
+ /**
+ * Property used to override whether the device uses headless system user mode.
+ *
+ * <p>Only used on non-user builds.
+ *
+ * <p><b>NOTE: </b>setting this variable directly won't properly change the headless system user
+ * mode behavior and might put the device in a bad state; the system user mode should be changed
+ * using {@code cmd user set-system-user-mode-emulation} instead.
+ *
+ * @hide
+ */
+ public static final String SYSTEM_USER_MODE_EMULATION_PROPERTY =
+ "persist.debug.user_mode_emulation";
+
+ /** @hide */
+ public static final String SYSTEM_USER_MODE_EMULATION_DEFAULT = "default";
+ /** @hide */
+ public static final String SYSTEM_USER_MODE_EMULATION_FULL = "full";
+ /** @hide */
+ public static final String SYSTEM_USER_MODE_EMULATION_HEADLESS = "headless";
+
private static final String ACTION_CREATE_USER = "android.os.action.CREATE_USER";
/**
@@ -2001,13 +2023,22 @@ public class UserManager {
* @return Whether guest user is always ephemeral
* @hide
*/
- @TestApi
- public static boolean isGuestUserEphemeral() {
+ public static boolean isGuestUserAlwaysEphemeral() {
return Resources.getSystem()
.getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
}
/**
+ * @return true, when we want to enable user manager API and UX to allow
+ * guest user ephemeral state change based on user input
+ * @hide
+ */
+ public static boolean isGuestUserAllowEphemeralStateChange() {
+ return Resources.getSystem()
+ .getBoolean(com.android.internal.R.bool.config_guestUserAllowEphemeralStateChange);
+ }
+
+ /**
* Checks whether the device is running in a headless system user mode.
*
* <p>Headless system user mode means the {@link #isSystemUser() system user} runs system
@@ -2017,7 +2048,28 @@ public class UserManager {
* @return whether the device is running in a headless system user mode.
*/
public static boolean isHeadlessSystemUserMode() {
- return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
+ final boolean realMode = RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
+ if (!Build.isDebuggable()) {
+ return realMode;
+ }
+
+ final String emulatedMode = SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY);
+ switch (emulatedMode) {
+ case SYSTEM_USER_MODE_EMULATION_FULL:
+ Log.d(TAG, "isHeadlessSystemUserMode(): emulating as false");
+ return false;
+ case SYSTEM_USER_MODE_EMULATION_HEADLESS:
+ Log.d(TAG, "isHeadlessSystemUserMode(): emulating as true");
+ return true;
+ case SYSTEM_USER_MODE_EMULATION_DEFAULT:
+ case "": // property not set
+ return realMode;
+ default:
+ Log.wtf(TAG, "isHeadlessSystemUserMode(): invalid value of property "
+ + SYSTEM_USER_MODE_EMULATION_PROPERTY + " (" + emulatedMode + "); using"
+ + " default value (headless=" + realMode + ")");
+ return realMode;
+ }
}
/**
@@ -3431,6 +3483,20 @@ public class UserManager {
if (guest != null) {
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+
+ if (UserManager.isGuestUserAllowEphemeralStateChange()) {
+ // Mark guest as (changeably) ephemeral if REMOVE_GUEST_ON_EXIT is 1
+ // This is done so that a user via a UI controller can choose to
+ // make a guest as ephemeral or not.
+ // Settings.Global.REMOVE_GUEST_ON_EXIT holds the choice on what the guest state
+ // should be, with default being ephemeral.
+ boolean resetGuestOnExit = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, 1) == 1;
+
+ if (resetGuestOnExit && !guest.isEphemeral()) {
+ setUserEphemeral(guest.id, true);
+ }
+ }
}
return guest;
} catch (ServiceSpecificException e) {
@@ -4795,17 +4861,14 @@ public class UserManager {
* shares media with its parent user (the user that created this profile).
* Returns false for any other type of user.
*
- * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission, otherwise the
- * caller must be in the same profile group as the user.
- *
* @return true if the user shares media with its parent user, false otherwise.
* @hide
*/
@SystemApi
- @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
- @UserHandleAware
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ Manifest.permission.MANAGE_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
public boolean isMediaSharedWithParent() {
try {
@@ -4948,6 +5011,31 @@ public class UserManager {
}
/**
+ * Set the user as ephemeral or non-ephemeral.
+ *
+ * If the user was initially created as ephemeral then this
+ * method has no effect and false is returned.
+ *
+ * @param userId the user's integer id
+ * @param enableEphemeral true: change user state to ephemeral,
+ * false: change user state to non-ephemeral
+ * @return true: user now has the desired ephemeral state,
+ * false: desired user ephemeral state could not be set
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS})
+ public boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
+ try {
+ return mService.setUserEphemeral(userId, enableEphemeral);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Updates the context user's name.
*
* @param name the new name for the user
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index ec1c57d675c1..237f6ed819f6 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -413,10 +413,8 @@ public abstract class VibrationEffect implements Parcelable {
* {@link #startWaveform(VibrationEffect.VibrationParameter)}.
*
* @see VibrationEffect.WaveformBuilder
- * @hide
*/
@NonNull
- @TestApi
public static WaveformBuilder startWaveform() {
return new WaveformBuilder();
}
@@ -433,10 +431,8 @@ public abstract class VibrationEffect implements Parcelable {
* @return The {@link VibrationEffect.WaveformBuilder} started with the initial parameters.
*
* @see VibrationEffect.WaveformBuilder
- * @hide
*/
@NonNull
- @TestApi
public static WaveformBuilder startWaveform(@NonNull VibrationParameter initialParameter) {
WaveformBuilder builder = startWaveform();
builder.addTransition(Duration.ZERO, initialParameter);
@@ -458,10 +454,8 @@ public abstract class VibrationEffect implements Parcelable {
* @return The {@link VibrationEffect.WaveformBuilder} started with the initial parameters.
*
* @see VibrationEffect.WaveformBuilder
- * @hide
*/
@NonNull
- @TestApi
public static WaveformBuilder startWaveform(@NonNull VibrationParameter initialParameter1,
@NonNull VibrationParameter initialParameter2) {
WaveformBuilder builder = startWaveform();
@@ -875,9 +869,7 @@ public abstract class VibrationEffect implements Parcelable {
/**
* Exception thrown when adding an element to a {@link Composition} that already ends in an
* indefinitely repeating effect.
- * @hide
*/
- @TestApi
public static final class UnreachableAfterRepeatingIndefinitelyException
extends IllegalStateException {
UnreachableAfterRepeatingIndefinitelyException() {
@@ -946,10 +938,8 @@ public abstract class VibrationEffect implements Parcelable {
*
* @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
* ending with a repeating effect.
- * @hide
*/
@NonNull
- @TestApi
public Composition addOffDuration(@NonNull Duration duration) {
int durationMs = (int) duration.toMillis();
Preconditions.checkArgumentNonnegative(durationMs, "Off period must be non-negative");
@@ -975,10 +965,8 @@ public abstract class VibrationEffect implements Parcelable {
*
* @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
* ending with a repeating effect.
- * @hide
*/
@NonNull
- @TestApi
public Composition addEffect(@NonNull VibrationEffect effect) {
return addSegments(effect);
}
@@ -999,10 +987,8 @@ public abstract class VibrationEffect implements Parcelable {
* @throws IllegalArgumentException if the given effect is already repeating indefinitely.
* @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
* ending with a repeating effect.
- * @hide
*/
@NonNull
- @TestApi
public Composition repeatEffectIndefinitely(@NonNull VibrationEffect effect) {
Preconditions.checkArgument(effect.getDuration() < Long.MAX_VALUE,
"Can't repeat an indefinitely repeating effect. Consider addEffect instead.");
@@ -1216,9 +1202,7 @@ public abstract class VibrationEffect implements Parcelable {
* .build();}</pre>
*
* @see VibrationEffect#startWaveform
- * @hide
*/
- @TestApi
public static final class WaveformBuilder {
// Epsilon used for float comparison of amplitude and frequency values on transitions.
private static final float EPSILON = 1e-5f;
@@ -1399,10 +1383,8 @@ public abstract class VibrationEffect implements Parcelable {
* <p>Examples of concrete parameters are the vibration amplitude or frequency.
*
* @see VibrationEffect.WaveformBuilder
- * @hide
*/
@SuppressWarnings("UserHandleName") // This is not a regular set of parameters, no *Params.
- @TestApi
public static class VibrationParameter {
VibrationParameter() {
}
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 465d90d36698..7f0d6349f57f 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -212,9 +212,7 @@ public abstract class Vibrator {
*
* @return True if the hardware can control the frequency of the vibrations independently of
* the vibration amplitude, false otherwise.
- * @hide
*/
- @TestApi
public boolean hasFrequencyControl() {
// We currently can only control frequency of the vibration using the compose PWLE method.
return getInfo().hasCapability(
@@ -238,9 +236,7 @@ public abstract class Vibrator {
* @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown, not
* applicable, or if this vibrator is a composite of multiple physical devices with different
* frequencies.
- * @hide
*/
- @TestApi
public float getResonantFrequency() {
return getInfo().getResonantFrequencyHz();
}
@@ -251,9 +247,7 @@ public abstract class Vibrator {
* @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown, not
* applicable, or if this vibrator is a composite of multiple physical devices with different
* Q factors.
- * @hide
*/
- @TestApi
public float getQFactor() {
return getInfo().getQFactor();
}
@@ -268,9 +262,7 @@ public abstract class Vibrator {
* frequency control. If this vibrator is a composite of multiple physical devices then this
* will return a profile supported in all devices, or null if the intersection is empty or not
* available.
- * @hide
*/
- @TestApi
@Nullable
public VibratorFrequencyProfile getFrequencyProfile() {
VibratorInfo.FrequencyProfile frequencyProfile = getInfo().getFrequencyProfile();
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index ff126e12cf61..1f686e5c449c 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -8,3 +8,4 @@ sahanas@google.com
abkaur@google.com
chiangi@google.com
narayan@google.com
+dipankarb@google.com
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfile.java b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
index afc0007afd42..0f2aa157d94c 100644
--- a/core/java/android/os/vibrator/VibratorFrequencyProfile.java
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
@@ -18,7 +18,6 @@ package android.os.vibrator;
import android.annotation.FloatRange;
import android.annotation.NonNull;
-import android.annotation.TestApi;
import android.os.VibratorInfo;
import com.android.internal.util.Preconditions;
@@ -39,9 +38,7 @@ import com.android.internal.util.Preconditions;
* frequency increment between each pair of amplitude values.
*
* <p>Vibrators without independent frequency control do not have a frequency profile.
- * @hide
*/
-@TestApi
public final class VibratorFrequencyProfile {
private final VibratorInfo.FrequencyProfile mFrequencyProfile;
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index b5466b6d3cb5..49f4bf71c172 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -5,10 +5,14 @@ evanxinchen@google.com
ewol@google.com
guojing@google.com
jaysullivan@google.com
+kvakil@google.com
+mrulhania@google.com
+narayan@google.com
+ntmyren@google.com
olekarg@google.com
pyuli@google.com
-ntmyren@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+raphk@google.com
+rmacgregor@google.com
+sergeynv@google.com
theianchen@google.com
zhanghai@google.com
diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md
index dfe748b09464..e61ecd8781d0 100644
--- a/core/java/android/permission/Permissions.md
+++ b/core/java/android/permission/Permissions.md
@@ -71,9 +71,9 @@ Any app can request any permission via adding an entry in the manifest file like
A requested permission does not necessarily mean that the permission is granted. When and how a
permission is granted depends on the protection level of the permission. If no protection level is
-set, the permission will always be granted. Such "normal" permissions can still be useful as it
-will be easy to find apps using a certain functionality on app stores and by checking `dumpsys
-package`.
+set, it will default to `normal` and the permission will always be granted if requested. Such
+`normal` permissions can still be useful as it will be easy to find apps using a certain
+functionality on app stores and by checking `dumpsys package`.
#### Checking a permission
@@ -686,17 +686,37 @@ able to call APIs not available to other apps. This is implemented by granting p
these system apps and then enforcing the permissions in the API similar to other [install time
permissions](#checking-a-permission).
-System apps are not different from regular apps, but the protection levels (e.g.
+System apps are not different from regular apps, but the protection flags (e.g.
[privileged](#privileged-permissions), [preinstalled](#preinstalled-permissions)) mentioned in this
section are more commonly used by system apps.
-### Multiple permission levels
+### Permission protection level
-It is possible to assign multiple protection levels to a permission. Very common combinations are
-for example adding `signature` to all permissions to make sure the platform signed apps can be
-granted the permission, e.g. `privileged|signature`.
+Every permission has a protection level (`android:protectionlevel`), which is a combination of one
+required protection (`PermissionInfo.getProtection()`) and multiple optional protection flags
+(`PermissionInfo.getProtectionFlags()`).
-The permission will be granted if the app qualifies for _any_ of the permission levels.
+The protection can be one of the following:
+
+- [`normal`](#requesting-a-permission): The permission will be granted to apps requesting it in
+their manifest.
+- [`dangerous`](#runtime-permissions): The permission will be a runtime permission.
+- [`signature`](#signature-permissions): The permission will be granted to apps being signed with
+the same certificate as the app defining the permission. If the permission is a platform permission,
+it means those apps need to be platform-signed.
+- `internal`: This is a no-op protection so that it won't allow granting the permission by itself.
+However, it will be useful when defining permissions that should only be granted according to its
+protection flags, e.g. `internal|role` for a role-only permission.
+
+There are various optional protection flags that can be added to protection level, in addition to
+the required protection, e.g. [appop](#app_op-permissions),
+[preinstalled](#preinstalled-permissions), [privileged](#privileged-permissions),
+[installer](#limited-permissions), [role](#role-protected-permissions) and
+[development](#development-permissions).
+
+The permission will be granted to an app if it meets _any_ of the protection or protection flags (an
+`OR` relationship). For example, `signature|privileged` allows the permission to be granted to
+platform-signed apps as well as privileged apps.
### App-op permissions
@@ -716,18 +736,15 @@ and special behavior. Hence this section is a guideline, not a rule.
#### Defining an app-op permission
Only the platform can reasonably define an app-op permission. The permission is defined in the
-platforms manifest using the `appop` protection level
+platforms manifest using the `appop` protection flag:
```xml
<manifest package="android">
<permission android:name="android.permission.MY_APPOP_PERMISSION"
- android:protectionLevel="appop|signature" />
+ android:protectionLevel="signature|appop" />
</manifest>
```
-Almost always the protection level is app-op | something else, like
-[signature](#signature-permissions) (in the case above) or [privileged](#privileged-permissions).
-
#### Checking an app-op permission
The `PermissionChecker` utility can check app-op permissions with the [same syntax as runtime
@@ -913,12 +930,12 @@ See
> Not recommended
-By adding the `development` protection level to any permissions the permission can be granted via
+By adding the `development` protection flag to any permissions the permission can be granted via
the `pm grant` shell command. This appears to be useful for development and testing, but it is very
highly discouraged. Any user can grant them permanently via adb, hence adding this tag removes
all guarantees the permission might otherwise provide.
-### Other protection levels
+### Other protection flags
There are other levels (such as `runtime`) but they are for special purposes on should not be
used by platform developers.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 13a3ec8c0562..d40303035c89 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -313,6 +313,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
/**
+ * Namespace for all Kernel Multi-Gen LRU feature.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native";
+
+ /**
* Namespace for all netd related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d2a86eb31870..ad91ae2f68e5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3785,6 +3785,10 @@ public final class Settings {
private static boolean putStringForUser(ContentResolver resolver, String name, String value,
String tag, boolean makeDefault, int userHandle, boolean overrideableByRestore) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "System.putString(name=" + name + ", value=" + value + ") for "
+ + userHandle);
+ }
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, value is unchanged.");
@@ -5678,6 +5682,33 @@ public final class Settings {
@Readable
public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls";
+ /** Controls whether bluetooth is on or off on wearable devices.
+ *
+ * <p>The valid values for this key are: 0 (disabled) or 1 (enabled).
+ *
+ * @hide
+ */
+ public static final String CLOCKWORK_BLUETOOTH_SETTINGS_PREF = "cw_bt_settings_pref";
+
+ /**
+ * Controls whether the unread notification dot indicator is shown on wearable devices.
+ *
+ * <p>The valid values for this key are: 0 (disabled) or 1 (enabled).
+ *
+ * @hide
+ */
+ public static final String UNREAD_NOTIFICATION_DOT_INDICATOR =
+ "unread_notification_dot_indicator";
+
+ /**
+ * Controls whether auto-launching media controls is enabled on wearable devices.
+ *
+ * <p>The valid values for this key are: 0 (disabled) or 1 (enabled).
+ *
+ * @hide
+ */
+ public static final String AUTO_LAUNCH_MEDIA_CONTROLS = "auto_launch_media_controls";
+
// Settings moved to Settings.Secure
/**
@@ -6206,6 +6237,10 @@ public final class Settings {
public static boolean putStringForUser(@NonNull ContentResolver resolver,
@NonNull String name, @Nullable String value, @Nullable String tag,
boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Secure.putString(name=" + name + ", value=" + value + ") for "
+ + userHandle);
+ }
if (MOVED_TO_GLOBAL.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
+ " to android.provider.Settings.Global");
@@ -9141,6 +9176,57 @@ public final class Settings {
public static final String SCREENSAVER_ENABLED_COMPLICATIONS =
"screensaver_enabled_complications";
+
+ /**
+ * Default, indicates that the user has not yet started the dock setup flow.
+ *
+ * @hide
+ */
+ public static final int DOCK_SETUP_NOT_STARTED = 0;
+
+ /**
+ * Indicates that the user has started but not yet completed dock setup.
+ * One of the possible states for {@link #DOCK_SETUP_STATE}.
+ *
+ * @hide
+ */
+ public static final int DOCK_SETUP_STARTED = 1;
+
+ /**
+ * Indicates that the user has snoozed dock setup and will complete it later.
+ * One of the possible states for {@link #DOCK_SETUP_STATE}.
+ *
+ * @hide
+ */
+ public static final int DOCK_SETUP_PAUSED = 2;
+
+ /**
+ * Indicates that the user has completed dock setup.
+ * One of the possible states for {@link #DOCK_SETUP_STATE}.
+ *
+ * @hide
+ */
+ public static final int DOCK_SETUP_COMPLETED = 10;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ DOCK_SETUP_NOT_STARTED,
+ DOCK_SETUP_STARTED,
+ DOCK_SETUP_PAUSED,
+ DOCK_SETUP_COMPLETED
+ })
+ public @interface DockSetupState {
+ }
+
+ /**
+ * Defines the user's current state of dock setup.
+ * The possible states are defined in {@link DockSetupState}.
+ *
+ * @hide
+ */
+ public static final String DOCK_SETUP_STATE = "dock_setup_state";
+
/**
* The default NFC payment component
* @hide
@@ -9661,6 +9747,13 @@ public final class Settings {
"biometric_debug_enabled";
/**
+ * Whether or not virtual sensors are enabled.
+ * @hide
+ */
+ @Readable
+ public static final String BIOMETRIC_VIRTUAL_ENABLED = "biometric_virtual_enabled";
+
+ /**
* Whether or not biometric is allowed on Keyguard.
* @hide
*/
@@ -10673,6 +10766,16 @@ public final class Settings {
public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled";
/**
+ * Controls the 'Sunlight boost' toggle in wearable devices (high brightness mode).
+ *
+ * Valid values for this key are: '0' (disabled) or '1' (enabled).
+ *
+ * @hide
+ */
+ public static final String HBM_SETTING_KEY =
+ "com.android.server.display.HBM_SETTING_KEY";
+
+ /**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
@@ -10820,6 +10923,15 @@ public final class Settings {
"launcher_taskbar_education_showing";
/**
+ * Whether or not adaptive charging feature is enabled by user.
+ * Type: int (0 for false, 1 for true)
+ * Default: 1
+ *
+ * @hide
+ */
+ public static final String ADAPTIVE_CHARGING_ENABLED = "adaptive_charging_enabled";
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
*/
@@ -10945,6 +11057,14 @@ public final class Settings {
public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked";
/**
+ * Whether guest user should be removed on exit from guest mode.
+ * <p>
+ * Type: int
+ * @hide
+ */
+ public static final String REMOVE_GUEST_ON_EXIT = "remove_guest_on_exit";
+
+ /**
* Whether applying ramping ringer on incoming phone call ringtone.
* <p>1 = apply ramping ringer
* <p>0 = do not apply ramping ringer
@@ -14410,6 +14530,18 @@ public final class Settings {
public static final String ANGLE_EGL_FEATURES = "angle_egl_features";
/**
+ * Comma-separated list of package names that ANGLE may have issues with
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST = "angle_deferlist";
+
+ /**
+ * Integer mode of the logic for applying `angle_deferlist`
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST_MODE = "angle_deferlist_mode";
+
+ /**
* Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
* The value is a boolean (1 or 0).
* @hide
@@ -16005,8 +16137,8 @@ public final class Settings {
@NonNull String name, @Nullable String value, @Nullable String tag,
boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
if (LOCAL_LOGV) {
- Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
- + " for " + userHandle);
+ Log.v(TAG, "Global.putString(name=" + name + ", value=" + value + ") for "
+ + userHandle);
}
// Global and Secure have the same access policy so we can forward writes
if (MOVED_TO_SECURE.contains(name)) {
@@ -16902,22 +17034,6 @@ public final class Settings {
public static final String SHOW_NEW_NOTIF_DISMISS = "show_new_notif_dismiss";
/**
- * Block untrusted touches mode.
- *
- * Can be one of:
- * <ul>
- * <li>0 = {@link BlockUntrustedTouchesMode#DISABLED}: Feature is off.
- * <li>1 = {@link BlockUntrustedTouchesMode#PERMISSIVE}: Untrusted touches are flagged
- * but not blocked
- * <li>2 = {@link BlockUntrustedTouchesMode#BLOCK}: Untrusted touches are blocked
- * </ul>
- *
- * @hide
- */
- @Readable
- public static final String BLOCK_UNTRUSTED_TOUCHES_MODE = "block_untrusted_touches";
-
- /**
* The maximum allowed obscuring opacity by UID to propagate touches.
*
* For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams
@@ -17055,18 +17171,6 @@ public final class Settings {
"obtain_paired_device_location";
/**
- * Whether the device is in retail mode.
- * @hide
- */
- public static final String RETAIL_MODE = "retail_mode";
-
- // Possible retail mode states
- /** @hide */
- public static final int RETAIL_MODE_CONSUMER = 0;
- /** @hide */
- public static final int RETAIL_MODE_RETAIL = 1;
-
- /**
* The play store availability on companion phone.
* @hide
*/
@@ -17233,12 +17337,6 @@ public final class Settings {
public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string";
/**
- * How round the corners of square screens are.
- * @hide
- */
- public static final String CORNER_ROUNDNESS = "corner_roundness";
-
- /**
* Whether the physical button has been set.
* @hide
*/
@@ -17312,6 +17410,18 @@ public final class Settings {
public static final String AMBIENT_TILT_TO_BRIGHT = "ambient_tilt_to_bright";
/**
+ * Whether touch and hold to edit WF is enabled
+ * @hide
+ */
+ public static final String TOUCH_AND_HOLD_WATCH_FACE = "touch_and_hold_watchface";
+
+ /**
+ * Whether bedtime mode is enabled.
+ * @hide
+ */
+ public static final String BEDTIME_MODE = "bedtime_mode";
+
+ /**
* Whether the current watchface is decomposable.
* @hide
*/
@@ -17475,6 +17585,14 @@ public final class Settings {
"wear_activity_auto_resume_timeout_set_by_user";
/**
+ * The maximum times that we are allowed to reset the activity auto-resume timeout
+ * timer.
+ * @hide
+ */
+ public static final String WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MAX_RESET_COUNT =
+ "wear_activity_auto_resume_timeout_max_reset_count";
+
+ /**
* If burn in protection is enabled.
* @hide
*/
@@ -17529,6 +17647,18 @@ public final class Settings {
* @hide
*/
public static final String WET_MODE_ON = "wet_mode_on";
+
+ /*
+ * Whether the screen-unlock (keyguard) sound is enabled.
+ * @hide
+ */
+ public static final String SCREEN_UNLOCK_SOUND_ENABLED = "screen_unlock_sound_enabled";
+
+ /*
+ * Whether charging sounds are enabled.
+ * @hide
+ */
+ public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled";
}
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 5ff926336751..154fcab8827d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -930,6 +930,11 @@ public final class Telephony {
/**
* Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate an sms
* was received while the phone was in encrypted state.
+ * <p>
+ * This result code is only used on devices that use Full Disk Encryption. Support for
+ * Full Disk Encryption was entirely removed in API level 33, having been replaced by
+ * File Based Encryption. Devices that use File Based Encryption never reject incoming
+ * SMS messages due to the encryption state.
*/
public static final int RESULT_SMS_RECEIVED_WHILE_ENCRYPTED = 9;
@@ -4803,6 +4808,13 @@ public final class Telephony {
"phone_number_source_ims";
/**
+ * TelephonyProvider column name for last used TP - message Reference
+ *
+ * @hide
+ */
+ public static final String COLUMN_TP_MESSAGE_REF = "tp_message_ref";
+
+ /**
* TelephonyProvider column name for the device's preferred usage setting.
*
* @hide
diff --git a/core/java/android/security/attestationverification/AttestationVerificationManager.java b/core/java/android/security/attestationverification/AttestationVerificationManager.java
index db783ceabcdb..2e61db1b932a 100644
--- a/core/java/android/security/attestationverification/AttestationVerificationManager.java
+++ b/core/java/android/security/attestationverification/AttestationVerificationManager.java
@@ -226,10 +226,10 @@ public class AttestationVerificationManager {
public static final int PROFILE_SELF_TRUSTED = 2;
/**
- * A system-defined profile which verifies that the attesting environment environment is similar
- * to the current device in terms of security model and security configuration. This category is
- * fairly broad and most securely configured Android devices should qualify, along with a
- * variety of non-Android devices.
+ * A system-defined profile which verifies that the attesting environment is similar to the
+ * current device in terms of security model and security configuration. This category is fairly
+ * broad and most securely configured Android devices should qualify, along with a variety of
+ * non-Android devices.
*/
public static final int PROFILE_PEER_DEVICE = 3;
@@ -321,4 +321,52 @@ public class AttestationVerificationManager {
/** Requirements bundle parameter for a challenge. */
public static final String PARAM_CHALLENGE = "localbinding.challenge";
+
+ /** @hide */
+ public static String localBindingTypeToString(@LocalBindingType int localBindingType) {
+ final String text;
+ switch (localBindingType) {
+ case TYPE_UNKNOWN:
+ text = "UNKNOWN";
+ break;
+
+ case TYPE_APP_DEFINED:
+ text = "APP_DEFINED";
+ break;
+
+ case TYPE_PUBLIC_KEY:
+ text = "PUBLIC_KEY";
+ break;
+
+ case TYPE_CHALLENGE:
+ text = "CHALLENGE";
+ break;
+
+ default:
+ return Integer.toString(localBindingType);
+ }
+ return text + "(" + localBindingType + ")";
+ }
+
+ /** @hide */
+ public static String verificationResultCodeToString(@VerificationResult int resultCode) {
+ final String text;
+ switch (resultCode) {
+ case RESULT_UNKNOWN:
+ text = "UNKNOWN";
+ break;
+
+ case RESULT_SUCCESS:
+ text = "SUCCESS";
+ break;
+
+ case RESULT_FAILURE:
+ text = "FAILURE";
+ break;
+
+ default:
+ return Integer.toString(resultCode);
+ }
+ return text + "(" + resultCode + ")";
+ }
}
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 8331550a7ef5..cc1b6cda82bb 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -32,7 +32,7 @@ import android.view.autofill.AutofillId;
import com.android.internal.util.DataClass;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
/**
* This class represents a context for each fill request made via {@link
@@ -95,7 +95,7 @@ public final class FillContext implements Parcelable {
* @hide
*/
@NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) {
- final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+ final ArrayDeque<ViewNode> nodesToProcess = new ArrayDeque<>();
final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length];
// Indexes of foundNodes that are not found yet
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 1507c87c0452..327cda3360bb 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -97,7 +97,7 @@ public final class FillRequest implements Parcelable {
*/
public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
- // The flag value 0x20 has been used.
+ // The flag value 0x20 has been defined in AutofillManager.
/**
* Indicates the request supports fill dialog presentation for the fields, the
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index bf64d06d4ff0..f6a7c8eb8c4b 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -21,8 +21,6 @@ import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
-import com.android.internal.R;
-
/**
* The Activity used by the {@link DreamService} to draw screensaver content
* on the screen. This activity runs in dream application's process, but is started by a
@@ -66,17 +64,4 @@ public class DreamActivity extends Activity {
callback.onActivityCreated(this);
}
}
-
- @Override
- public void onResume() {
- super.onResume();
- overridePendingTransition(R.anim.dream_activity_open_enter,
- R.anim.dream_activity_open_exit);
- }
-
- @Override
- public void finishAndRemoveTask() {
- super.finishAndRemoveTask();
- overridePendingTransition(0, R.anim.dream_activity_close_exit);
- }
}
diff --git a/core/java/android/service/games/IGameService.aidl b/core/java/android/service/games/IGameService.aidl
index 38c8416117e0..c8d4da0c3300 100644
--- a/core/java/android/service/games/IGameService.aidl
+++ b/core/java/android/service/games/IGameService.aidl
@@ -23,7 +23,12 @@ import android.service.games.IGameServiceController;
* @hide
*/
oneway interface IGameService {
+ @RequiresNoPermission
void connected(in IGameServiceController gameServiceController);
+
+ @RequiresNoPermission
void disconnected();
+
+ @RequiresNoPermission
void gameStarted(in GameStartedEvent gameStartedEvent);
}
diff --git a/core/java/android/service/games/IGameServiceController.aidl b/core/java/android/service/games/IGameServiceController.aidl
index 886f519b6605..d696ec3a3afe 100644
--- a/core/java/android/service/games/IGameServiceController.aidl
+++ b/core/java/android/service/games/IGameServiceController.aidl
@@ -20,5 +20,6 @@ package android.service.games;
* @hide
*/
oneway interface IGameServiceController {
+ @EnforcePermission("MANAGE_GAME_ACTIVITY")
void createGameSession(int taskId);
-} \ No newline at end of file
+}
diff --git a/core/java/android/service/games/IGameSession.aidl b/core/java/android/service/games/IGameSession.aidl
index 49c36c6a301c..fca1632b1a0d 100644
--- a/core/java/android/service/games/IGameSession.aidl
+++ b/core/java/android/service/games/IGameSession.aidl
@@ -20,7 +20,12 @@ package android.service.games;
* @hide
*/
oneway interface IGameSession {
+ @RequiresNoPermission
void onDestroyed();
+
+ @RequiresNoPermission
void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean visibleDueToGesture);
+
+ @RequiresNoPermission
void onTaskFocusChanged(boolean focused);
}
diff --git a/core/java/android/service/games/IGameSessionController.aidl b/core/java/android/service/games/IGameSessionController.aidl
index fd994044775f..99c66125a6c5 100644
--- a/core/java/android/service/games/IGameSessionController.aidl
+++ b/core/java/android/service/games/IGameSessionController.aidl
@@ -23,7 +23,9 @@ import com.android.internal.infra.AndroidFuture;
* @hide
*/
oneway interface IGameSessionController {
+ @EnforcePermission("MANAGE_GAME_ACTIVITY")
void takeScreenshot(int taskId, in AndroidFuture gameScreenshotResultFuture);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)")
+
+ @EnforcePermission("MANAGE_GAME_ACTIVITY")
void restartGame(in int taskId);
}
diff --git a/core/java/android/service/games/IGameSessionService.aidl b/core/java/android/service/games/IGameSessionService.aidl
index 37cde561f549..c39dd48bbbe3 100644
--- a/core/java/android/service/games/IGameSessionService.aidl
+++ b/core/java/android/service/games/IGameSessionService.aidl
@@ -28,6 +28,7 @@ import com.android.internal.infra.AndroidFuture;
* @hide
*/
oneway interface IGameSessionService {
+ @RequiresNoPermission
void create(
in IGameSessionController gameSessionController,
in CreateGameSessionRequest createGameSessionRequest,
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b9e60a11a8f3..65f0824a9b78 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -258,6 +258,11 @@ public abstract class NotificationListenerService extends Service {
public static final int REASON_CLEAR_DATA = 21;
/** Notification was canceled due to an assistant adjustment update. */
public static final int REASON_ASSISTANT_CANCEL = 22;
+ /**
+ * Notification was canceled when entering lockdown mode, which turns off
+ * Smart Lock, fingerprint unlocking, and notifications on the lock screen.
+ */
+ public static final int REASON_LOCKDOWN = 23;
/**
* @hide
@@ -285,6 +290,7 @@ public abstract class NotificationListenerService extends Service {
REASON_CHANNEL_REMOVED,
REASON_CLEAR_DATA,
REASON_ASSISTANT_CANCEL,
+ REASON_LOCKDOWN,
})
public @interface NotificationCancelReason{};
diff --git a/core/java/android/service/oemlock/IOemLockService.aidl b/core/java/android/service/oemlock/IOemLockService.aidl
index 99cffc5c5b8b..d656854e8b36 100644
--- a/core/java/android/service/oemlock/IOemLockService.aidl
+++ b/core/java/android/service/oemlock/IOemLockService.aidl
@@ -22,14 +22,21 @@ package android.service.oemlock;
* @hide
*/
interface IOemLockService {
+ @EnforcePermission("MANAGE_CARRIER_OEM_UNLOCK_STATE")
String getLockName();
+ @EnforcePermission("MANAGE_CARRIER_OEM_UNLOCK_STATE")
void setOemUnlockAllowedByCarrier(boolean allowed, in byte[] signature);
+ @EnforcePermission("MANAGE_CARRIER_OEM_UNLOCK_STATE")
boolean isOemUnlockAllowedByCarrier();
+ @EnforcePermission("MANAGE_USER_OEM_UNLOCK_STATE")
void setOemUnlockAllowedByUser(boolean allowed);
+ @EnforcePermission("MANAGE_USER_OEM_UNLOCK_STATE")
boolean isOemUnlockAllowedByUser();
+ @EnforcePermission(anyOf = {"READ_OEM_UNLOCK_STATE", "OEM_UNLOCK_STATE"})
boolean isOemUnlockAllowed();
+ @EnforcePermission(anyOf = {"READ_OEM_UNLOCK_STATE", "OEM_UNLOCK_STATE"})
boolean isDeviceOemUnlocked();
}
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index 0d290eee5777..ce38bb823fb3 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -135,7 +135,7 @@ class QuickAccessWalletServiceInfo {
return null;
}
- private static class ServiceMetadata {
+ static class ServiceMetadata {
@Nullable
private final String mSettingsActivity;
@Nullable
@@ -161,7 +161,7 @@ class QuickAccessWalletServiceInfo {
}
}
- private static ServiceMetadata parseServiceMetadata(Context context, ServiceInfo serviceInfo) {
+ static ServiceMetadata parseServiceMetadata(Context context, ServiceInfo serviceInfo) {
PackageManager pm = context.getPackageManager();
final XmlResourceParser parser =
serviceInfo.loadXmlMetaData(pm, QuickAccessWalletService.SERVICE_META_DATA);
diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java
index 328750fe7780..a2ca5a3e2f35 100644
--- a/core/java/android/service/voice/AbstractHotwordDetector.java
+++ b/core/java/android/service/voice/AbstractHotwordDetector.java
@@ -22,6 +22,7 @@ import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
+import android.app.compat.CompatChanges;
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.Handler;
@@ -65,6 +66,13 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
}
/**
+ * Method to be called for the detector to ready/register itself with underlying system
+ * services.
+ */
+ abstract void initialize(@Nullable PersistableBundle options,
+ @Nullable SharedMemory sharedMemory);
+
+ /**
* Detect hotword from an externally supplied stream of data.
*
* @return true if the request to start recognition succeeded
@@ -73,7 +81,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
public boolean startRecognition(
@NonNull ParcelFileDescriptor audioStream,
@NonNull AudioFormat audioFormat,
- @Nullable PersistableBundle options) {
+ @Nullable PersistableBundle options) throws IllegalDetectorStateException {
if (DEBUG) {
Slog.i(TAG, "#recognizeHotword");
}
@@ -98,19 +106,22 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
* Set configuration and pass read-only data to hotword detection service.
*
* @param options Application configuration data to provide to the
- * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or
- * other contents that can be used to communicate with other processes.
+ * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable
+ * objects or other contents that can be used to communicate with other processes.
* @param sharedMemory The unrestricted data blob to provide to the
- * {@link HotwordDetectionService}. Use this to provide the hotword models data or other
- * such data to the trusted process.
- *
- * @throws IllegalStateException if this AlwaysOnHotwordDetector wasn't specified to use a
- * {@link HotwordDetectionService} when it was created. In addition, if this
- * AlwaysOnHotwordDetector is in an invalid or error state.
+ * {@link HotwordDetectionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of
+ * Android Tiramisu or above and attempts to start a recognition when the detector is
+ * not able based on the state. Because the caller receives updates via an asynchronous
+ * callback and the state of the detector can change without caller's knowledge, a
+ * checked exception is thrown.
+ * @throws IllegalStateException if this HotwordDetector wasn't specified to use a
+ * {@link HotwordDetectionService} when it was created.
*/
@Override
public void updateState(@Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ @Nullable SharedMemory sharedMemory) throws IllegalDetectorStateException {
if (DEBUG) {
Slog.d(TAG, "updateState()");
}
@@ -156,9 +167,13 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
}
}
- protected void throwIfDetectorIsNoLongerActive() {
+ protected void throwIfDetectorIsNoLongerActive() throws IllegalDetectorStateException {
if (!mIsDetectorActive.get()) {
Slog.e(TAG, "attempting to use a destroyed detector which is no longer active");
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "attempting to use a destroyed detector which is no longer active");
+ }
throw new IllegalStateException(
"attempting to use a destroyed detector which is no longer active");
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index bc42da6b4c97..d01e7feba36e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -18,6 +18,7 @@ package android.service.voice;
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
+import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -27,6 +28,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.ActivityThread;
+import android.app.compat.CompatChanges;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -50,9 +52,11 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
@@ -62,8 +66,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
/**
* A class that lets a VoiceInteractionService implementation interact with
@@ -275,11 +282,12 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* The metadata of the Keyphrase, derived from the enrollment application.
* This may be null if this keyphrase isn't supported by the enrollment application.
*/
+ @GuardedBy("mLock")
@Nullable
private KeyphraseMetadata mKeyphraseMetadata;
private final KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
private final IVoiceInteractionManagerService mModelManagementService;
- private final IVoiceInteractionSoundTriggerSession mSoundTriggerSession;
+ private IVoiceInteractionSoundTriggerSession mSoundTriggerSession;
private final SoundTriggerListener mInternalCallback;
private final Callback mExternalCallback;
private final Handler mHandler;
@@ -287,6 +295,9 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
private final int mTargetSdkVersion;
private final boolean mSupportHotwordDetectionService;
+ @GuardedBy("mLock")
+ private boolean mIsAvailabilityOverriddenByTestApi = false;
+ @GuardedBy("mLock")
private int mAvailability = STATE_NOT_READY;
/**
@@ -788,8 +799,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionManagerService modelManagementService, int targetSdkVersion,
- boolean supportHotwordDetectionService, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ boolean supportHotwordDetectionService) {
super(modelManagementService, callback,
supportHotwordDetectionService ? DETECTOR_TYPE_TRUSTED_HOTWORD_DSP
: DETECTOR_TYPE_NORMAL);
@@ -803,6 +813,12 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
mModelManagementService = modelManagementService;
mTargetSdkVersion = targetSdkVersion;
mSupportHotwordDetectionService = supportHotwordDetectionService;
+ }
+
+ @Override
+ void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
+ // TODO: transition to use an API that is not updateState to provide
+ // onHotwordDetectionServiceInitialized status to external callback
if (mSupportHotwordDetectionService) {
updateStateLocked(options, sharedMemory, mInternalCallback,
DETECTOR_TYPE_TRUSTED_HOTWORD_DSP);
@@ -810,30 +826,40 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
try {
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
- mSoundTriggerSession = mModelManagementService.createSoundTriggerSessionAsOriginator(
- identity, mBinder);
+ mSoundTriggerSession =
+ mModelManagementService.createSoundTriggerSessionAsOriginator(
+ identity, mBinder);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
- new RefreshAvailabiltyTask().execute();
+ new RefreshAvailabilityTask().execute();
}
/**
* {@inheritDoc}
*
- * @throws IllegalStateException if this AlwaysOnHotwordDetector wasn't specified to use a
- * {@link HotwordDetectionService} when it was created. In addition, if this
- * AlwaysOnHotwordDetector is in an invalid or error state.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and this AlwaysOnHotwordDetector wasn't specified to use a
+ * {@link HotwordDetectionService} when it was created. In addition, the exception can
+ * be thrown if this AlwaysOnHotwordDetector is in an invalid or error state.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if
+ * this AlwaysOnHotwordDetector wasn't specified to use a
+ * {@link HotwordDetectionService} when it was created. In addition, the exception can
+ * be thrown if this AlwaysOnHotwordDetector is in an invalid or error state.
*/
@Override
public final void updateState(@Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ @Nullable SharedMemory sharedMemory) throws IllegalDetectorStateException {
synchronized (mLock) {
if (!mSupportHotwordDetectionService) {
throw new IllegalStateException(
"updateState called, but it doesn't support hotword detection service");
}
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "updateState called on an invalid detector or error state");
+ }
throw new IllegalStateException(
"updateState called on an invalid detector or error state");
}
@@ -843,6 +869,48 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
/**
+ * Test API for manipulating the voice engine and sound model availability.
+ *
+ * After overriding the availability status, the client's
+ * {@link Callback#onAvailabilityChanged(int)} will be called to reflect the updated state.
+ *
+ * When this override is set, all system updates to availability will be ignored.
+ * @hide
+ */
+ @TestApi
+ public void overrideAvailability(int availability) {
+ synchronized (mLock) {
+ // ENROLLED state requires there to be metadata about the sound model so a fake one
+ // is created.
+ if (mKeyphraseMetadata == null && availability == STATE_KEYPHRASE_ENROLLED) {
+ Set<Locale> fakeSupportedLocales = new HashSet<>();
+ fakeSupportedLocales.add(mLocale);
+ mKeyphraseMetadata = new KeyphraseMetadata(1, mText, fakeSupportedLocales,
+ AlwaysOnHotwordDetector.RECOGNITION_MODE_VOICE_TRIGGER);
+ }
+
+ mAvailability = availability;
+ mIsAvailabilityOverriddenByTestApi = true;
+ notifyStateChangedLocked();
+ }
+ }
+
+ /**
+ * Test API for clearing an availability override set by {@link #overrideAvailability(int)}
+ *
+ * This method will restore the availability to the current system state.
+ * @hide
+ */
+ @TestApi
+ public void resetAvailability() {
+ synchronized (mLock) {
+ mIsAvailabilityOverriddenByTestApi = false;
+ }
+ // Execute a refresh availability task - which should then notify of a change.
+ new RefreshAvailabilityTask().execute();
+ }
+
+ /**
* Test API to simulate to trigger hardware recognition event for test.
*
* @hide
@@ -878,28 +946,46 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* @see #RECOGNITION_MODE_USER_IDENTIFICATION
* @see #RECOGNITION_MODE_VOICE_TRIGGER
*
- * @throws UnsupportedOperationException if the keyphrase itself isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above. Because the caller receives availability updates via an asynchronous
+ * callback, it may be due to the availability changing while this call is performed.
+ * - Throws if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 Android if the recognition isn't supported. Callers should only call this method
+ * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to
+ * avoid this exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below Android API level
+ * 33 if the detector is in an invalid or error state. This may happen if another
+ * detector has been instantiated or the {@link VoiceInteractionService} hosting this
+ * detector has been shut down.
*/
- public @RecognitionModes int getSupportedRecognitionModes() {
+ public @RecognitionModes
+ int getSupportedRecognitionModes() throws IllegalDetectorStateException {
if (DBG) Slog.d(TAG, "getSupportedRecognitionModes()");
synchronized (mLock) {
return getSupportedRecognitionModesLocked();
}
}
- private int getSupportedRecognitionModesLocked() {
+ @GuardedBy("mLock")
+ private int getSupportedRecognitionModesLocked() throws IllegalDetectorStateException {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException("getSupportedRecognitionModes called on an"
+ + " invalid detector or error state");
+ }
throw new IllegalStateException(
"getSupportedRecognitionModes called on an invalid detector or error state");
}
// This method only makes sense if we can actually support a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED || mKeyphraseMetadata == null) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException("Getting supported recognition modes for"
+ + " the keyphrase is not supported");
+ }
throw new UnsupportedOperationException(
"Getting supported recognition modes for the keyphrase is not supported");
}
@@ -926,6 +1012,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
+ @GuardedBy("mLock")
private int getSupportedAudioCapabilitiesLocked() {
try {
ModuleProperties properties =
@@ -949,30 +1036,77 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
*
* @param recognitionFlags The flags to control the recognition properties.
+ * @param data Additional pass-through data to the system voice engine along with the
+ * startRecognition request. This data is intended to provide additional parameters
+ * when starting the opaque sound model.
* @return Indicates whether the call succeeded or not.
- * @throws UnsupportedOperationException if the recognition isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and attempts to start a recognition when the detector is not able based on
+ * the availability state. This can be thrown even if the state has been checked before
+ * calling this method because the caller receives availability updates via an
+ * asynchronous callback, it may be due to the availability changing while this call is
+ * performed.
+ * - Throws if the recognition isn't supported.
+ * Callers should only call this method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * - Also throws if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 Android if the recognition isn't supported. Callers should only call this method
+ * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to
+ * avoid this exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below Android API level
+ * 33 if the detector is in an invalid or error state. This may happen if another
+ * detector has been instantiated or the {@link VoiceInteractionService} hosting this
+ * detector has been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
- public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
- if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
+ public boolean startRecognition(@RecognitionFlags int recognitionFlags, @NonNull byte[] data)
+ throws IllegalDetectorStateException {
synchronized (mLock) {
- if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
- throw new IllegalStateException(
- "startRecognition called on an invalid detector or error state");
- }
-
- // Check if we can start/stop a recognition.
- if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
- throw new UnsupportedOperationException(
- "Recognition for the given keyphrase is not supported");
- }
+ return startRecognitionLocked(recognitionFlags, data)
+ == STATUS_OK;
+ }
+ }
- return startRecognitionLocked(recognitionFlags) == STATUS_OK;
+ /**
+ * Starts recognition for the associated keyphrase.
+ * Caller must be the active voice interaction service via
+ * Settings.Secure.VOICE_INTERACTION_SERVICE.
+ *
+ * @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ * @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ *
+ * @param recognitionFlags The flags to control the recognition properties.
+ * @return Indicates whether the call succeeded or not.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and attempts to start a recognition when the detector is not able based on
+ * the availability state. This can be thrown even if the state has been checked before
+ * calling this method because the caller receives availability updates via an
+ * asynchronous callback, it may be due to the availability changing while this call is
+ * performed.
+ * - Throws if the recognition isn't supported.
+ * Callers should only call this method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * - Also throws if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 if the recognition isn't supported. Callers should only call this method after a
+ * supported state callback on {@link Callback#onAvailabilityChanged(int)} to avoid this
+ * exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid or error state. This may happen if another detector has
+ * been instantiated or the {@link VoiceInteractionService} hosting this detector has
+ * been shut down.
+ */
+ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
+ public boolean startRecognition(@RecognitionFlags int recognitionFlags)
+ throws IllegalDetectorStateException {
+ if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
+ synchronized (mLock) {
+ return startRecognitionLocked(recognitionFlags, null /* data */) == STATUS_OK;
}
}
@@ -983,7 +1117,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
@Override
- public boolean startRecognition() {
+ public boolean startRecognition()
+ throws IllegalDetectorStateException {
return startRecognition(0);
}
@@ -993,28 +1128,44 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* Settings.Secure.VOICE_INTERACTION_SERVICE.
*
* @return Indicates whether the call succeeded or not.
- * @throws UnsupportedOperationException if the recognition isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of
+ * API level 33 or above and attempts to stop a recognition when the detector is
+ * not able based on the state. This can be thrown even if the state has been checked
+ * before calling this method because the caller receives availability updates via an
+ * asynchronous callback, it may be due to the availability changing while this call is
+ * performed.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 if the recognition isn't supported. Callers should only call this method after a
+ * supported state callback on {@link Callback#onAvailabilityChanged(int)} to avoid this
+ * exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid or error state. This may happen if another detector has
+ * been instantiated or the {@link VoiceInteractionService} hosting this detector has
+ * been shut down.
*/
// TODO: Remove this RequiresPermission since it isn't actually enforced. Also fix the javadoc
// about permissions enforcement (when it throws vs when it just returns false) for other
// methods in this class.
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
@Override
- public boolean stopRecognition() {
+ public boolean stopRecognition() throws IllegalDetectorStateException {
if (DBG) Slog.d(TAG, "stopRecognition()");
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "stopRecognition called on an invalid detector or error state");
+ }
throw new IllegalStateException(
"stopRecognition called on an invalid detector or error state");
}
// Check if we can start/stop a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "Recognition for the given keyphrase is not supported");
+ }
throw new UnsupportedOperationException(
"Recognition for the given keyphrase is not supported");
}
@@ -1039,18 +1190,28 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
* - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
* if API is not supported by HAL
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * if the detector is in an invalid or error state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid or error state. This may happen if another detector has
+ * been instantiated or the {@link VoiceInteractionService} hosting this detector has
+ * been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
- public int setParameter(@ModelParams int modelParam, int value) {
+ public int setParameter(@ModelParams int modelParam, int value)
+ throws IllegalDetectorStateException {
if (DBG) {
Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
}
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "setParameter called on an invalid detector or error state");
+ }
throw new IllegalStateException(
"setParameter called on an invalid detector or error state");
}
@@ -1071,18 +1232,27 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
*
* @param modelParam {@link ModelParams}
* @return value of parameter
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * if the detector is in an invalid or error state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if
+ * the detector is in an invalid or error state. This may happen if another detector has
+ * been instantiated or the {@link VoiceInteractionService} hosting this detector has
+ * been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
- public int getParameter(@ModelParams int modelParam) {
+ public int getParameter(@ModelParams int modelParam) throws IllegalDetectorStateException {
if (DBG) {
Slog.d(TAG, "getParameter(" + modelParam + ")");
}
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "getParameter called on an invalid detector or error state");
+ }
throw new IllegalStateException(
"getParameter called on an invalid detector or error state");
}
@@ -1100,19 +1270,29 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
*
* @param modelParam {@link ModelParams}
* @return supported range of parameter, null if not supported
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * if the detector is in an invalid or error state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if
+ * the detector is in an invalid or error state. This may happen if another detector has
+ * been instantiated or the {@link VoiceInteractionService} hosting this detector has
+ * been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
@Nullable
- public ModelParamRange queryParameter(@ModelParams int modelParam) {
+ public ModelParamRange queryParameter(@ModelParams int modelParam)
+ throws IllegalDetectorStateException {
if (DBG) {
Slog.d(TAG, "queryParameter(" + modelParam + ")");
}
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "queryParameter called on an invalid detector or error state");
+ }
throw new IllegalStateException(
"queryParameter called on an invalid detector or error state");
}
@@ -1129,15 +1309,25 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* otherwise {@link #createReEnrollIntent()} should be preferred.
*
* @return An {@link Intent} to start enrollment for the given keyphrase.
- * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above.
+ * - Thrown if managing they keyphrase isn't supported. Callers should only call this
+ * method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * - Thrown if the detector is in an invalid state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 if managing they keyphrase isn't supported. Callers should only call this method
+ * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to
+ * avoid this exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid state. This may happen if another detector has been
+ * instantiated or the {@link VoiceInteractionService} hosting this detector has been
+ * shut down.
*/
@Nullable
- public Intent createEnrollIntent() {
+ public Intent createEnrollIntent() throws IllegalDetectorStateException {
if (DBG) Slog.d(TAG, "createEnrollIntent");
synchronized (mLock) {
return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_ENROLL);
@@ -1151,15 +1341,25 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
*
* @return An {@link Intent} to start un-enrollment for the given keyphrase.
- * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above.
+ * - Thrown if managing they keyphrase isn't supported. Callers should only call this
+ * method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * - Thrown if the detector is in an invalid state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 if managing they keyphrase isn't supported. Callers should only call this method
+ * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to
+ * avoid this exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid state. This may happen if another detector has been
+ * instantiated or the {@link VoiceInteractionService} hosting this detector has been
+ * shut down.
*/
@Nullable
- public Intent createUnEnrollIntent() {
+ public Intent createUnEnrollIntent() throws IllegalDetectorStateException {
if (DBG) Slog.d(TAG, "createUnEnrollIntent");
synchronized (mLock) {
return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_UN_ENROLL);
@@ -1173,30 +1373,50 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
*
* @return An {@link Intent} to start re-enrollment for the given keyphrase.
- * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
- * Callers should only call this method after a supported state callback on
- * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid or error state.
- * This may happen if another detector has been instantiated or the
- * {@link VoiceInteractionService} hosting this detector has been shut down.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above.
+ * - Thrown if managing they keyphrase isn't supported. Callers should only call this
+ * method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * - Thrown if the detector is in an invalid state. This may happen if another detector
+ * has been instantiated or the {@link VoiceInteractionService} hosting this detector
+ * has been shut down.
+ * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level
+ * 33 if managing they keyphrase isn't supported. Callers should only call this method
+ * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to
+ * avoid this exception.
+ * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the
+ * detector is in an invalid state. This may happen if another detector has been
+ * instantiated or the {@link VoiceInteractionService} hosting this detector has been
+ * shut down.
*/
@Nullable
- public Intent createReEnrollIntent() {
+ public Intent createReEnrollIntent() throws IllegalDetectorStateException {
if (DBG) Slog.d(TAG, "createReEnrollIntent");
synchronized (mLock) {
return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_RE_ENROLL);
}
}
- private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action) {
+ @GuardedBy("mLock")
+ private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action)
+ throws IllegalDetectorStateException {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "getManageIntent called on an invalid detector or error state");
+ }
throw new IllegalStateException(
- "getManageIntent called on an invalid detector or error state");
+ "getManageIntent called on an invalid detector or error state");
}
// This method only makes sense if we can actually support a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED
&& mAvailability != STATE_KEYPHRASE_UNENROLLED) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "Managing the given keyphrase is not supported");
+ }
throw new UnsupportedOperationException(
"Managing the given keyphrase is not supported");
}
@@ -1212,24 +1432,29 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
public void destroy() {
synchronized (mLock) {
if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
- stopRecognition();
+ try {
+ stopRecognition();
+ } catch (Exception e) {
+ Log.i(TAG, "failed to stopRecognition in destroy", e);
+ }
}
mAvailability = STATE_INVALID;
+ mIsAvailabilityOverriddenByTestApi = false;
notifyStateChangedLocked();
-
- if (mSupportHotwordDetectionService) {
- try {
- mModelManagementService.shutdownHotwordDetectionService();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
}
super.destroy();
}
/**
+ * @hide
+ */
+ @Override
+ public boolean isUsingHotwordDetectionService() {
+ return mSupportHotwordDetectionService;
+ }
+
+ /**
* Reloads the sound models from the service.
*
* @hide
@@ -1244,6 +1469,15 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
return;
}
+ // Because this method reflects an update from the system service models, we should not
+ // update the client of an availability change when the availability has been overridden
+ // via a test API.
+ if (mIsAvailabilityOverriddenByTestApi) {
+ Slog.w(TAG, "Suppressing system availability update. "
+ + "Availability is overridden by test API.");
+ return;
+ }
+
// Stop the recognition before proceeding.
// This is done because we want to stop the recognition on an older model if it changed
// or was deleted.
@@ -1263,11 +1497,37 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
// Execute a refresh availability task - which should then notify of a change.
- new RefreshAvailabiltyTask().execute();
+ new RefreshAvailabilityTask().execute();
}
}
- private int startRecognitionLocked(int recognitionFlags) {
+ @GuardedBy("mLock")
+ private int startRecognitionLocked(int recognitionFlags,
+ @Nullable byte[] data) throws IllegalDetectorStateException {
+ if (DBG) {
+ Slog.d(TAG, "startRecognition("
+ + recognitionFlags
+ + ", " + Arrays.toString(data) + ")");
+ }
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "startRecognition called on an invalid detector or error state");
+ }
+ throw new IllegalStateException(
+ "startRecognition called on an invalid detector or error state");
+ }
+
+ // Check if we can start/stop a recognition.
+ if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
+ if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) {
+ throw new IllegalDetectorStateException(
+ "Recognition for the given keyphrase is not supported");
+ }
+ throw new UnsupportedOperationException(
+ "Recognition for the given keyphrase is not supported");
+ }
+
KeyphraseRecognitionExtra[] recognitionExtra = new KeyphraseRecognitionExtra[1];
// TODO: Do we need to do something about the confidence level here?
recognitionExtra[0] = new KeyphraseRecognitionExtra(mKeyphraseMetadata.getId(),
@@ -1291,7 +1551,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
code = mSoundTriggerSession.startRecognition(
mKeyphraseMetadata.getId(), mLocale.toLanguageTag(), mInternalCallback,
new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
- recognitionExtra, null /* additional data */, audioCapabilities),
+ recognitionExtra, data, audioCapabilities),
runInBatterySaver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1303,6 +1563,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
return code;
}
+ @GuardedBy("mLock")
private int stopRecognitionLocked() {
int code;
try {
@@ -1318,6 +1579,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
return code;
}
+ @GuardedBy("mLock")
private int setParameterLocked(@ModelParams int modelParam, int value) {
try {
int code = mSoundTriggerSession.setParameter(mKeyphraseMetadata.getId(), modelParam,
@@ -1333,6 +1595,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
+ @GuardedBy("mLock")
private int getParameterLocked(@ModelParams int modelParam) {
try {
return mSoundTriggerSession.getParameter(mKeyphraseMetadata.getId(), modelParam);
@@ -1341,6 +1604,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
+ @GuardedBy("mLock")
@Nullable
private ModelParamRange queryParameterLocked(@ModelParams int modelParam) {
try {
@@ -1357,15 +1621,19 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
+ @GuardedBy("mLock")
private void updateAndNotifyStateChangedLocked(int availability) {
if (DBG) {
Slog.d(TAG, "Hotword availability changed from " + mAvailability
+ " -> " + availability);
}
- mAvailability = availability;
+ if (!mIsAvailabilityOverriddenByTestApi) {
+ mAvailability = availability;
+ }
notifyStateChangedLocked();
}
+ @GuardedBy("mLock")
private void notifyStateChangedLocked() {
Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED);
message.arg1 = mAvailability;
@@ -1487,7 +1755,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
- class RefreshAvailabiltyTask extends AsyncTask<Void, Void, Void> {
+ class RefreshAvailabilityTask extends AsyncTask<Void, Void, Void> {
@Override
public Void doInBackground(Void... params) {
@@ -1555,7 +1823,26 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
}
+ @Override
+ public boolean equals(Object obj) {
+ if (CompatChanges.isChangeEnabled(MULTIPLE_ACTIVE_HOTWORD_DETECTORS)) {
+ if (!(obj instanceof AlwaysOnHotwordDetector)) {
+ return false;
+ }
+ AlwaysOnHotwordDetector other = (AlwaysOnHotwordDetector) obj;
+ return TextUtils.equals(mText, other.mText) && mLocale.equals(other.mLocale);
+ }
+
+ return super.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mText, mLocale);
+ }
+
/** @hide */
+ @Override
public void dump(String prefix, PrintWriter pw) {
synchronized (mLock) {
pw.print(prefix); pw.print("Text="); pw.println(mText);
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index d755d3877275..c6de8438bccb 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -39,6 +39,7 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.speech.IRecognitionServiceManager;
import android.util.Log;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
@@ -127,6 +128,8 @@ public abstract class HotwordDetectionService extends Service {
@Nullable
private ContentCaptureManager mContentCaptureManager;
+ @Nullable
+ private IRecognitionServiceManager mIRecognitionServiceManager;
private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() {
@Override
@@ -196,6 +199,11 @@ public abstract class HotwordDetectionService extends Service {
}
@Override
+ public void updateRecognitionServiceManager(IRecognitionServiceManager manager) {
+ mIRecognitionServiceManager = manager;
+ }
+
+ @Override
public void ping(IRemoteCallback callback) throws RemoteException {
callback.sendResult(null);
}
@@ -222,6 +230,9 @@ public abstract class HotwordDetectionService extends Service {
public @Nullable Object getSystemService(@ServiceName @NonNull String name) {
if (Context.CONTENT_CAPTURE_MANAGER_SERVICE.equals(name)) {
return mContentCaptureManager;
+ } else if (Context.SPEECH_RECOGNITION_SERVICE.equals(name)
+ && mIRecognitionServiceManager != null) {
+ return mIRecognitionServiceManager.asBinder();
} else {
return super.getSystemService(name);
}
@@ -243,13 +254,26 @@ public abstract class HotwordDetectionService extends Service {
/**
* Called when the device hardware (such as a DSP) detected the hotword, to request second stage
* validation before handing over the audio to the {@link AlwaysOnHotwordDetector}.
- * <p>
- * After {@code callback} is invoked or {@code timeoutMillis} has passed, and invokes the
+ *
+ * <p>After {@code callback} is invoked or {@code timeoutMillis} has passed, and invokes the
* appropriate {@link AlwaysOnHotwordDetector.Callback callback}.
*
+ * <p>When responding to a detection event, the
+ * {@link HotwordDetectedResult#getHotwordPhraseId()} must match a keyphrase ID listed
+ * in the eventPayload's
+ * {@link AlwaysOnHotwordDetector.EventPayload#getKeyphraseRecognitionExtras()} list. This is
+ * forcing the intention of the {@link HotwordDetectionService} to validate an event from the
+ * voice engine and not augment its result.
+ *
* @param eventPayload Payload data for the hardware detection event. This may contain the
- * trigger audio, if requested when calling
- * {@link AlwaysOnHotwordDetector#startRecognition(int)}.
+ * trigger audio, if requested when calling
+ * {@link AlwaysOnHotwordDetector#startRecognition(int)}.
+ * Each {@link AlwaysOnHotwordDetector} will be associated with at minimum a unique
+ * keyphrase ID indicated by
+ * {@link AlwaysOnHotwordDetector.EventPayload#getKeyphraseRecognitionExtras()}[0].
+ * Any extra
+ * {@link android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra}'s
+ * in the eventPayload represent additional phrases detected by the voice engine.
* @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
* the application fails to abide by the timeout, system will close the
* microphone and cancel the operation.
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index 96fd8bbda016..1a0dc8945b63 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -23,10 +23,16 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.media.AudioFormat;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.SharedMemory;
+import android.util.AndroidException;
+
+import java.io.PrintWriter;
/**
* Basic functionality for hotword detectors.
@@ -37,6 +43,23 @@ import android.os.SharedMemory;
public interface HotwordDetector {
/**
+ * Prior to API level 33, API calls of {@link android.service.voice.HotwordDetector} could
+ * return both {@link java.lang.IllegalStateException} or
+ * {@link java.lang.UnsupportedOperationException} depending on the detector's underlying state.
+ * This lead to confusing behavior as the underlying state of the detector can be modified
+ * without the knowledge of the caller via system service layer updates.
+ *
+ * This change ID, when enabled, changes the API calls to only throw checked exception
+ * {@link android.service.voice.HotwordDetector.IllegalDetectorStateException} when checking
+ * against state information modified by both the caller and the system services.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ long HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION = 226355112L;
+
+ /**
* Indicates that it is a non-trusted hotword detector.
*
* @hide
@@ -74,16 +97,26 @@ public interface HotwordDetector {
* Calling this again while recognition is active does nothing.
*
* @return true if the request to start recognition succeeded
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and attempts to start a recognition when the detector is not able based on
+ * the state. This can be thrown even if the state has been checked before calling this
+ * method because the caller receives updates via an asynchronous callback, and the
+ * state of the detector can change concurrently to the caller calling this method.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
- boolean startRecognition();
+ boolean startRecognition() throws IllegalDetectorStateException;
/**
* Stops hotword recognition.
*
* @return true if the request to stop recognition succeeded
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and attempts to stop a recognition when the detector is not able based on
+ * the state. This can be thrown even if the state has been checked before calling this
+ * method because the caller receives updates via an asynchronous callback, and the
+ * state of the detector can change concurrently to the caller calling this method.
*/
- boolean stopRecognition();
+ boolean stopRecognition() throws IllegalDetectorStateException;
/**
* Starts hotword recognition on audio coming from an external connected microphone.
@@ -97,26 +130,37 @@ public interface HotwordDetector {
* PersistableBundle does not allow any remotable objects or other contents that can be
* used to communicate with other processes.
* @return true if the request to start recognition succeeded
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and attempts to start a recognition when the detector is not able based on
+ * the state. This can be thrown even if the state has been checked before calling this
+ * method because the caller receives updates via an asynchronous callback, and the
+ * state of the detector can change concurrently to the caller calling this method.
*/
boolean startRecognition(
@NonNull ParcelFileDescriptor audioStream,
@NonNull AudioFormat audioFormat,
- @Nullable PersistableBundle options);
+ @Nullable PersistableBundle options) throws IllegalDetectorStateException;
/**
* Set configuration and pass read-only data to hotword detection service.
*
* @param options Application configuration data to provide to the
- * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or
- * other contents that can be used to communicate with other processes.
+ * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable
+ * objects or other contents that can be used to communicate with other processes.
* @param sharedMemory The unrestricted data blob to provide to the
- * {@link HotwordDetectionService}. Use this to provide the hotword models data or other
- * such data to the trusted process.
- *
+ * {@link HotwordDetectionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
+ * or above and the detector is not able to perform the operation based on the
+ * underlying state. This can be thrown even if the state has been checked before
+ * calling this method because the caller receives updates via an asynchronous callback,
+ * and the state of the detector can change concurrently to the caller calling this
+ * method.
* @throws IllegalStateException if this HotwordDetector wasn't specified to use a
- * {@link HotwordDetectionService} when it was created.
+ * {@link HotwordDetectionService} when it was created.
*/
- void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory);
+ void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory)
+ throws IllegalDetectorStateException;
/**
* Invalidates this hotword detector so that any future calls to this result
@@ -132,6 +176,13 @@ public interface HotwordDetector {
/**
* @hide
*/
+ default boolean isUsingHotwordDetectionService() {
+ throw new UnsupportedOperationException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
+ * @hide
+ */
static String detectorTypeToString(int detectorType) {
switch (detectorType) {
case DETECTOR_TYPE_NORMAL:
@@ -145,6 +196,11 @@ public interface HotwordDetector {
}
}
+ /** @hide */
+ default void dump(String prefix, PrintWriter pw) {
+ throw new UnsupportedOperationException("Not implemented. Must override in a subclass.");
+ }
+
/**
* The callback to notify of detection events.
*/
@@ -205,4 +261,14 @@ public interface HotwordDetector {
*/
void onHotwordDetectionServiceRestarted();
}
+
+ /**
+ * {@link HotwordDetector} specific exception thrown when the underlying state of the detector
+ * is invalid for the given action.
+ */
+ class IllegalDetectorStateException extends AndroidException {
+ IllegalDetectorStateException(String message) {
+ super(message);
+ }
+ }
}
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index f2a93f100986..9ef930707f07 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -26,6 +26,7 @@ import android.os.PersistableBundle;
import android.os.SharedMemory;
import android.service.voice.IDspHotwordDetectionCallback;
import android.view.contentcapture.IContentCaptureManager;
+import android.speech.IRecognitionServiceManager;
/**
* Provide the interface to communicate with hotword detection service.
@@ -57,6 +58,9 @@ oneway interface IHotwordDetectionService {
in IContentCaptureManager contentCaptureManager,
in ContentCaptureOptions options);
+ void updateRecognitionServiceManager(
+ in IRecognitionServiceManager recognitionServiceManager);
+
/**
* Simply requests the service to trigger the callback, so that the system can check its
* identity.
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 68fa130b0003..02561c9410e3 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
@@ -57,8 +58,6 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
SoftwareHotwordDetector(
IVoiceInteractionManagerService managerService,
AudioFormat audioFormat,
- PersistableBundle options,
- SharedMemory sharedMemory,
HotwordDetector.Callback callback) {
super(managerService, callback, DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE);
@@ -66,6 +65,12 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
mAudioFormat = audioFormat;
mCallback = callback;
mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ @Override
+ void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
+ // TODO: transition to use an API that is not updateState to provide
+ // onHotwordDetectionServiceInitialized status to external callback
updateStateLocked(options, sharedMemory,
new InitializationStateListener(mHandler, mCallback),
DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE);
@@ -73,7 +78,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
@RequiresPermission(RECORD_AUDIO)
@Override
- public boolean startRecognition() {
+ public boolean startRecognition() throws IllegalDetectorStateException {
if (DEBUG) {
Slog.i(TAG, "#startRecognition");
}
@@ -96,7 +101,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
/** TODO: stopRecognition */
@RequiresPermission(RECORD_AUDIO)
@Override
- public boolean stopRecognition() {
+ public boolean stopRecognition() throws IllegalDetectorStateException {
if (DEBUG) {
Slog.i(TAG, "#stopRecognition");
}
@@ -113,17 +118,23 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
@Override
public void destroy() {
- stopRecognition();
- maybeCloseExistingSession();
-
try {
- mManagerService.shutdownHotwordDetectionService();
- } catch (RemoteException ex) {
- ex.rethrowFromSystemServer();
+ stopRecognition();
+ } catch (Exception e) {
+ Log.i(TAG, "failed to stopRecognition in destroy", e);
}
+ maybeCloseExistingSession();
super.destroy();
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isUsingHotwordDetectionService() {
+ return true;
+ }
+
private void maybeCloseExistingSession() {
// TODO: needs to be synchronized.
// TODO: implement this
@@ -251,6 +262,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
}
/** @hide */
+ @Override
public void dump(String prefix, PrintWriter pw) {
// TODO: implement this
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index bf0cfbe49f31..1170237a346e 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -24,12 +24,16 @@ import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.Service;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.media.voice.KeyphraseModelManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -89,6 +93,37 @@ public class VoiceInteractionService extends Service {
*/
public static final String SERVICE_META_DATA = "android.voice_interaction";
+ /**
+ * For apps targeting Build.VERSION_CODES.TRAMISU and above, implementors of this
+ * service can create multiple AlwaysOnHotwordDetector instances in parallel. They will
+ * also e ale to create a single SoftwareHotwordDetector in parallel with any other
+ * active AlwaysOnHotwordDetector instances.
+ *
+ * <p>Requirements when this change is enabled:
+ * <ul>
+ * <li>
+ * Any number of AlwaysOnHotwordDetector instances can be created in parallel
+ * as long as they are unique to any other active AlwaysOnHotwordDetector.
+ * </li>
+ * <li>
+ * Only a single instance of SoftwareHotwordDetector can be active at a given
+ * time. It can be active at the same time as any number of
+ * AlwaysOnHotwordDetector instances.
+ * </li>
+ * <li>
+ * To release that reference and any resources associated with that reference,
+ * HotwordDetector#destroy() must be called. An attempt to create an
+ * HotwordDetector equal to an active HotwordDetector will be rejected
+ * until HotwordDetector#destroy() is called on the active instance.
+ * </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
+ static final long MULTIPLE_ACTIVE_HOTWORD_DETECTORS = 193232191L;
+
IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
@Override
public void ready() {
@@ -133,8 +168,7 @@ public class VoiceInteractionService extends Service {
private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
- private AlwaysOnHotwordDetector mHotwordDetector;
- private SoftwareHotwordDetector mSoftwareHotwordDetector;
+ private final Set<HotwordDetector> mActiveHotwordDetectors = new ArraySet<>();
/**
* Called when a user has activated an affordance to launch voice assist from the Keyguard.
@@ -284,10 +318,12 @@ public class VoiceInteractionService extends Service {
private void onSoundModelsChangedInternal() {
synchronized (this) {
- if (mHotwordDetector != null) {
- // TODO: Stop recognition if a sound model that was being recognized gets deleted.
- mHotwordDetector.onSoundModelsChanged();
- }
+ // TODO: Stop recognition if a sound model that was being recognized gets deleted.
+ mActiveHotwordDetectors.forEach(detector -> {
+ if (detector instanceof AlwaysOnHotwordDetector) {
+ ((AlwaysOnHotwordDetector) detector).onSoundModelsChanged();
+ }
+ });
}
}
@@ -379,16 +415,31 @@ public class VoiceInteractionService extends Service {
throw new IllegalStateException("Not available until onReady() is called");
}
synchronized (mLock) {
- // Allow only one concurrent recognition via the APIs.
- safelyShutdownAllHotwordDetectors();
- mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
- mKeyphraseEnrollmentInfo, mSystemService,
+ if (!CompatChanges.isChangeEnabled(MULTIPLE_ACTIVE_HOTWORD_DETECTORS)) {
+ // Allow only one concurrent recognition via the APIs.
+ safelyShutdownAllHotwordDetectors();
+ }
+
+ AlwaysOnHotwordDetector dspDetector = new AlwaysOnHotwordDetector(keyphrase, locale,
+ callback, mKeyphraseEnrollmentInfo, mSystemService,
getApplicationContext().getApplicationInfo().targetSdkVersion,
- supportHotwordDetectionService, options, sharedMemory);
- mHotwordDetector.registerOnDestroyListener((detector) -> onDspHotwordDetectorDestroyed(
- (AlwaysOnHotwordDetector) detector));
+ supportHotwordDetectionService);
+ if (!mActiveHotwordDetectors.add(dspDetector)) {
+ throw new IllegalArgumentException(
+ "the keyphrase=" + keyphrase + " and locale=" + locale
+ + " are already used by another always-on detector");
+ }
+
+ try {
+ dspDetector.registerOnDestroyListener(this::onHotwordDetectorDestroyed);
+ dspDetector.initialize(options, sharedMemory);
+ } catch (Exception e) {
+ mActiveHotwordDetectors.remove(dspDetector);
+ dspDetector.destroy();
+ throw e;
+ }
+ return dspDetector;
}
- return mHotwordDetector;
}
/**
@@ -434,16 +485,34 @@ public class VoiceInteractionService extends Service {
throw new IllegalStateException("Not available until onReady() is called");
}
synchronized (mLock) {
- // Allow only one concurrent recognition via the APIs.
- safelyShutdownAllHotwordDetectors();
- mSoftwareHotwordDetector =
+ if (!CompatChanges.isChangeEnabled(MULTIPLE_ACTIVE_HOTWORD_DETECTORS)) {
+ // Allow only one concurrent recognition via the APIs.
+ safelyShutdownAllHotwordDetectors();
+ } else {
+ for (HotwordDetector detector : mActiveHotwordDetectors) {
+ if (detector instanceof SoftwareHotwordDetector) {
+ throw new IllegalArgumentException(
+ "There is already an active SoftwareHotwordDetector. "
+ + "It must be destroyed to create a new one.");
+ }
+ }
+ }
+
+ SoftwareHotwordDetector softwareHotwordDetector =
new SoftwareHotwordDetector(
- mSystemService, null, options, sharedMemory, callback);
- mSoftwareHotwordDetector.registerOnDestroyListener(
- (detector) -> onMicrophoneHotwordDetectorDestroyed(
- (SoftwareHotwordDetector) detector));
+ mSystemService, null, callback);
+
+ try {
+ softwareHotwordDetector.registerOnDestroyListener(
+ this::onHotwordDetectorDestroyed);
+ softwareHotwordDetector.initialize(options, sharedMemory);
+ } catch (Exception e) {
+ mActiveHotwordDetectors.remove(softwareHotwordDetector);
+ softwareHotwordDetector.destroy();
+ throw e;
+ }
+ return softwareHotwordDetector;
}
- return mSoftwareHotwordDetector;
}
/**
@@ -489,33 +558,34 @@ public class VoiceInteractionService extends Service {
private void safelyShutdownAllHotwordDetectors() {
synchronized (mLock) {
- if (mHotwordDetector != null) {
+ mActiveHotwordDetectors.forEach(detector -> {
try {
- mHotwordDetector.destroy();
+ detector.destroy();
} catch (Exception ex) {
- Log.i(TAG, "exception destroying AlwaysOnHotwordDetector", ex);
+ Log.i(TAG, "exception destroying HotwordDetector", ex);
}
- }
-
- if (mSoftwareHotwordDetector != null) {
- try {
- mSoftwareHotwordDetector.destroy();
- } catch (Exception ex) {
- Log.i(TAG, "exception destroying SoftwareHotwordDetector", ex);
- }
- }
+ });
}
}
- private void onDspHotwordDetectorDestroyed(@NonNull AlwaysOnHotwordDetector detector) {
+ private void onHotwordDetectorDestroyed(@NonNull HotwordDetector detector) {
synchronized (mLock) {
- mHotwordDetector = null;
+ mActiveHotwordDetectors.remove(detector);
+ shutdownHotwordDetectionServiceIfRequiredLocked();
}
}
- private void onMicrophoneHotwordDetectorDestroyed(@NonNull SoftwareHotwordDetector detector) {
- synchronized (mLock) {
- mSoftwareHotwordDetector = null;
+ private void shutdownHotwordDetectionServiceIfRequiredLocked() {
+ for (HotwordDetector detector : mActiveHotwordDetectors) {
+ if (detector.isUsingHotwordDetectionService()) {
+ return;
+ }
+ }
+
+ try {
+ mSystemService.shutdownHotwordDetectionService();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
}
}
@@ -540,18 +610,14 @@ public class VoiceInteractionService extends Service {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("VOICE INTERACTION");
synchronized (mLock) {
- pw.println(" AlwaysOnHotwordDetector");
- if (mHotwordDetector == null) {
- pw.println(" NULL");
- } else {
- mHotwordDetector.dump(" ", pw);
- }
-
- pw.println(" MicrophoneHotwordDetector");
- if (mSoftwareHotwordDetector == null) {
+ pw.println(" HotwordDetector(s)");
+ if (mActiveHotwordDetectors.size() == 0) {
pw.println(" NULL");
} else {
- mSoftwareHotwordDetector.dump(" ", pw);
+ mActiveHotwordDetectors.forEach(detector -> {
+ detector.dump(" ", pw);
+ pw.println();
+ });
}
}
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d598017dacaa..9679a6ab3acb 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -27,6 +27,7 @@ import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.ViewRootImpl.LOCAL_LAYOUT;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -1516,6 +1517,8 @@ public abstract class WallpaperService extends Service {
mVisible = visible;
reportVisibility();
if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+ } else {
+ AnimationHandler.requestAnimatorsEnabled(visible, this);
}
}
@@ -1536,14 +1539,16 @@ public abstract class WallpaperService extends Service {
// may have been destroyed so now we need to make
// sure it is re-created.
doOffsetsChanged(false);
- // force relayout to get new surface
- updateSurface(true, false, false);
+ // It will check mSurfaceCreated so no need to force relayout.
+ updateSurface(false /* forceRelayout */, false /* forceReport */,
+ false /* redrawNeeded */);
}
onVisibilityChanged(visible);
if (mReportedVisible && mFrozenRequested) {
if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update");
freeze();
}
+ AnimationHandler.requestAnimatorsEnabled(visible, this);
}
}
}
@@ -2072,6 +2077,8 @@ public abstract class WallpaperService extends Service {
return;
}
+ AnimationHandler.removeRequestor(this);
+
mDestroyed = true;
if (mIWallpaperEngine.mDisplayManager != null) {
diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS
index 32f482264103..462d8bed743c 100644
--- a/core/java/android/speech/OWNERS
+++ b/core/java/android/speech/OWNERS
@@ -1,3 +1,4 @@
volnov@google.com
eugeniom@google.com
schfan@google.com
+andreaambu@google.com
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 832db91cf516..3f6dddb36c9d 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -735,12 +735,12 @@ public class SpeechRecognizer {
return true;
}
- mManagerService = IRecognitionServiceManager.Stub.asInterface(
- ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE));
-
- if (DBG) {
- Log.i(TAG, "#maybeInitializeManagerService instantiated =" + mManagerService);
+ IBinder service = ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE);
+ if (service == null && mOnDevice) {
+ service = (IBinder) mContext.getSystemService(Context.SPEECH_RECOGNITION_SERVICE);
}
+ mManagerService = IRecognitionServiceManager.Stub.asInterface(service);
+
if (mManagerService == null) {
if (mListener != null) {
mListener.onError(ERROR_CLIENT);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 2f85d2b63840..6371da4f3776 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -25,6 +25,7 @@ import android.graphics.Paint;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
+import android.os.SystemProperties;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
@@ -32,6 +33,7 @@ import android.text.style.TabStopSpan;
import android.util.Log;
import android.util.Pools.SynchronizedPool;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
@@ -73,6 +75,13 @@ public class StaticLayout extends Layout {
* default values.
*/
public final static class Builder {
+ // The content length threshold to enable LINE_BREAK_WORD_STYLE_PHRASE.
+ private static final int DEFAULT_LINECOUNT_THRESHOLD_FOR_PHRASE = 3;
+
+ // The property of content length threshold to enable LINE_BREAK_WORD_STYLE_PHRASE.
+ private static final String PROPERTY_LINECOUNT_THRESHOLD_FOR_PHRASE =
+ "android.phrase.linecount.threshold";
+
private Builder() {}
/**
@@ -431,11 +440,55 @@ public class StaticLayout extends Layout {
*/
@NonNull
public StaticLayout build() {
+ reviseLineBreakConfig();
StaticLayout result = new StaticLayout(this);
Builder.recycle(this);
return result;
}
+ private void reviseLineBreakConfig() {
+ boolean autoPhraseBreaking = mLineBreakConfig.getAutoPhraseBreaking();
+ int wordStyle = mLineBreakConfig.getLineBreakWordStyle();
+ if (autoPhraseBreaking) {
+ if (wordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE) {
+ if (shouldEnablePhraseBreaking()) {
+ mLineBreakConfig = LineBreakConfig.getLineBreakConfig(
+ mLineBreakConfig.getLineBreakStyle(),
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
+ mLineBreakConfig.getAutoPhraseBreaking());
+ }
+ }
+ }
+ }
+
+ private boolean shouldEnablePhraseBreaking() {
+ if (TextUtils.isEmpty(mText) || mWidth <= 0) {
+ return false;
+ }
+ int lineLimit = SystemProperties.getInt(
+ PROPERTY_LINECOUNT_THRESHOLD_FOR_PHRASE,
+ DEFAULT_LINECOUNT_THRESHOLD_FOR_PHRASE);
+ double desiredWidth = (double) Layout.getDesiredWidth(mText, mStart,
+ mEnd, mPaint, mTextDir);
+ int lineCount = (int) Math.ceil(desiredWidth / mWidth);
+ if (lineCount > 0 && lineCount <= lineLimit) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get the line break word style.
+ *
+ * @return The current line break word style.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public int getLineBreakWordStyle() {
+ return mLineBreakConfig.getLineBreakWordStyle();
+ }
+
private CharSequence mText;
private int mStart;
private int mEnd;
@@ -1098,7 +1151,21 @@ public class StaticLayout extends Layout {
// TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
// one bit for start field
lines[off + TAB] |= hasTab ? TAB_MASK : 0;
- lines[off + HYPHEN] = hyphenEdit;
+ if (mEllipsized) {
+ if (ellipsize == TextUtils.TruncateAt.START) {
+ lines[off + HYPHEN] = packHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT,
+ unpackEndHyphenEdit(hyphenEdit));
+ } else if (ellipsize == TextUtils.TruncateAt.END) {
+ lines[off + HYPHEN] = packHyphenEdit(unpackStartHyphenEdit(hyphenEdit),
+ Paint.END_HYPHEN_EDIT_NO_EDIT);
+ } else { // Middle and marquee ellipsize should show text at the start/end edge.
+ lines[off + HYPHEN] = packHyphenEdit(
+ Paint.START_HYPHEN_EDIT_NO_EDIT, Paint.END_HYPHEN_EDIT_NO_EDIT);
+ }
+ } else {
+ lines[off + HYPHEN] = hyphenEdit;
+ }
+
lines[off + DIR] |= dir << DIR_SHIFT;
mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 7ac6ae186cc3..51e36657e769 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -70,7 +70,6 @@ import android.util.Log;
import android.util.Printer;
import android.view.View;
-import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
@@ -1230,8 +1229,8 @@ public class TextUtils {
/**
* Transforms a CharSequences to uppercase, copying the sources spans and keeping them spans as
- * much as possible close to their relative original places. In the case the the uppercase
- * string is identical to the sources, the source itself is returned instead of being copied.
+ * much as possible close to their relative original places. If uppercase string is identical
+ * to the sources, the source itself is returned instead of being copied.
*
* If copySpans is set, source must be an instance of Spanned.
*
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 471f2c2aecae..b9de93cc8ae0 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -21,7 +21,11 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
+import android.icu.text.DecimalFormat;
import android.icu.text.MeasureFormat;
+import android.icu.text.NumberFormat;
+import android.icu.text.UnicodeSet;
+import android.icu.text.UnicodeSetSpanner;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
import android.text.BidiFormatter;
@@ -30,6 +34,7 @@ import android.view.View;
import com.android.net.module.util.Inet4AddressUtils;
+import java.math.BigDecimal;
import java.util.Locale;
/**
@@ -64,7 +69,9 @@ public final class Formatter {
return context.getResources().getConfiguration().getLocales().get(0);
}
- /* Wraps the source string in bidi formatting characters in RTL locales */
+ /**
+ * Wraps the source string in bidi formatting characters in RTL locales.
+ */
private static String bidiWrap(@NonNull Context context, String source) {
final Locale locale = localeFromContext(context);
if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
@@ -101,9 +108,8 @@ public final class Formatter {
if (context == null) {
return "";
}
- final BytesResult res = formatBytes(context.getResources(), sizeBytes, flags);
- return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units));
+ final RoundedBytesResult res = RoundedBytesResult.roundBytes(sizeBytes, flags);
+ return bidiWrap(context, formatRoundedBytesResult(context, res));
}
/**
@@ -111,91 +117,174 @@ public final class Formatter {
* (showing fewer digits of precision).
*/
public static String formatShortFileSize(@Nullable Context context, long sizeBytes) {
- if (context == null) {
- return "";
- }
- final BytesResult res = formatBytes(context.getResources(), sizeBytes,
- FLAG_SI_UNITS | FLAG_SHORTER);
- return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units));
+ return formatFileSize(context, sizeBytes, FLAG_SI_UNITS | FLAG_SHORTER);
}
- /** {@hide} */
- @UnsupportedAppUsage
- public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
- final int unit = ((flags & FLAG_IEC_UNITS) != 0) ? 1024 : 1000;
- final boolean isNegative = (sizeBytes < 0);
- float result = isNegative ? -sizeBytes : sizeBytes;
- int suffix = com.android.internal.R.string.byteShort;
- long mult = 1;
- if (result > 900) {
- suffix = com.android.internal.R.string.kilobyteShort;
- mult = unit;
- result = result / unit;
- }
- if (result > 900) {
- suffix = com.android.internal.R.string.megabyteShort;
- mult *= unit;
- result = result / unit;
+ private static String getByteSuffixOverride(@NonNull Resources res) {
+ return res.getString(com.android.internal.R.string.byteShort);
+ }
+
+ private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) {
+ final NumberFormat numberFormatter = NumberFormat.getInstance(locale);
+ numberFormatter.setMinimumFractionDigits(fractionDigits);
+ numberFormatter.setMaximumFractionDigits(fractionDigits);
+ numberFormatter.setGroupingUsed(false);
+ if (numberFormatter instanceof DecimalFormat) {
+ // We do this only for DecimalFormat, since in the general NumberFormat case, calling
+ // setRoundingMode may throw an exception.
+ numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP);
}
- if (result > 900) {
- suffix = com.android.internal.R.string.gigabyteShort;
- mult *= unit;
- result = result / unit;
+ return numberFormatter;
+ }
+
+ private static String deleteFirstFromString(String source, String toDelete) {
+ final int location = source.indexOf(toDelete);
+ if (location == -1) {
+ return source;
+ } else {
+ return source.substring(0, location)
+ + source.substring(location + toDelete.length(), source.length());
}
- if (result > 900) {
- suffix = com.android.internal.R.string.terabyteShort;
- mult *= unit;
- result = result / unit;
+ }
+
+ private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter,
+ float value, MeasureUnit units) {
+ final MeasureFormat measureFormatter = MeasureFormat.getInstance(
+ locale, MeasureFormat.FormatWidth.SHORT, numberFormatter);
+ return measureFormatter.format(new Measure(value, units));
+ }
+
+ private static final UnicodeSetSpanner SPACES_AND_CONTROLS =
+ new UnicodeSetSpanner(new UnicodeSet("[[:Zs:][:Cf:]]").freeze());
+
+ private static String formatRoundedBytesResult(
+ @NonNull Context context, @NonNull RoundedBytesResult input) {
+ final Locale locale = localeFromContext(context);
+ final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits);
+ if (input.units == MeasureUnit.BYTE) {
+ // ICU spells out "byte" instead of "B".
+ final String formattedNumber = numberFormatter.format(input.value);
+ return context.getString(com.android.internal.R.string.fileSizeSuffix,
+ formattedNumber, getByteSuffixOverride(context.getResources()));
+ } else {
+ return formatMeasureShort(locale, numberFormatter, input.value, input.units);
}
- if (result > 900) {
- suffix = com.android.internal.R.string.petabyteShort;
- mult *= unit;
- result = result / unit;
+ }
+
+ /** {@hide} */
+ public static class RoundedBytesResult {
+ public final float value;
+ public final MeasureUnit units;
+ public final int fractionDigits;
+ public final long roundedBytes;
+
+ private RoundedBytesResult(
+ float value, MeasureUnit units, int fractionDigits, long roundedBytes) {
+ this.value = value;
+ this.units = units;
+ this.fractionDigits = fractionDigits;
+ this.roundedBytes = roundedBytes;
}
- // Note we calculate the rounded long by ourselves, but still let String.format()
- // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
- // floating point errors.
- final int roundFactor;
- final String roundFormat;
- if (mult == 1 || result >= 100) {
- roundFactor = 1;
- roundFormat = "%.0f";
- } else if (result < 1) {
- roundFactor = 100;
- roundFormat = "%.2f";
- } else if (result < 10) {
- if ((flags & FLAG_SHORTER) != 0) {
- roundFactor = 10;
- roundFormat = "%.1f";
- } else {
- roundFactor = 100;
- roundFormat = "%.2f";
+
+ /**
+ * Returns a RoundedBytesResult object based on the input size in bytes and the rounding
+ * flags. The result can be used for formatting.
+ */
+ public static RoundedBytesResult roundBytes(long sizeBytes, int flags) {
+ final int unit = ((flags & FLAG_IEC_UNITS) != 0) ? 1024 : 1000;
+ final boolean isNegative = (sizeBytes < 0);
+ float result = isNegative ? -sizeBytes : sizeBytes;
+ MeasureUnit units = MeasureUnit.BYTE;
+ long mult = 1;
+ if (result > 900) {
+ units = MeasureUnit.KILOBYTE;
+ mult = unit;
+ result = result / unit;
+ }
+ if (result > 900) {
+ units = MeasureUnit.MEGABYTE;
+ mult *= unit;
+ result = result / unit;
+ }
+ if (result > 900) {
+ units = MeasureUnit.GIGABYTE;
+ mult *= unit;
+ result = result / unit;
+ }
+ if (result > 900) {
+ units = MeasureUnit.TERABYTE;
+ mult *= unit;
+ result = result / unit;
}
- } else { // 10 <= result < 100
- if ((flags & FLAG_SHORTER) != 0) {
+ if (result > 900) {
+ units = MeasureUnit.PETABYTE;
+ mult *= unit;
+ result = result / unit;
+ }
+ // Note we calculate the rounded long by ourselves, but still let NumberFormat compute
+ // the rounded value. NumberFormat.format(0.1) might not return "0.1" due to floating
+ // point errors.
+ final int roundFactor;
+ final int roundDigits;
+ if (mult == 1 || result >= 100) {
roundFactor = 1;
- roundFormat = "%.0f";
- } else {
+ roundDigits = 0;
+ } else if (result < 1) {
roundFactor = 100;
- roundFormat = "%.2f";
+ roundDigits = 2;
+ } else if (result < 10) {
+ if ((flags & FLAG_SHORTER) != 0) {
+ roundFactor = 10;
+ roundDigits = 1;
+ } else {
+ roundFactor = 100;
+ roundDigits = 2;
+ }
+ } else { // 10 <= result < 100
+ if ((flags & FLAG_SHORTER) != 0) {
+ roundFactor = 1;
+ roundDigits = 0;
+ } else {
+ roundFactor = 100;
+ roundDigits = 2;
+ }
}
- }
- if (isNegative) {
- result = -result;
- }
- final String roundedString = String.format(roundFormat, result);
+ if (isNegative) {
+ result = -result;
+ }
- // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
- // it's okay (for now)...
- final long roundedBytes =
- (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
- : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
+ // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like
+ // 80PB so it's okay (for now)...
+ final long roundedBytes =
+ (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
+ : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
- final String units = res.getString(suffix);
+ return new RoundedBytesResult(result, units, roundDigits, roundedBytes);
+ }
+ }
- return new BytesResult(roundedString, units, roundedBytes);
+ /** {@hide} */
+ @UnsupportedAppUsage
+ public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
+ final RoundedBytesResult rounded = RoundedBytesResult.roundBytes(sizeBytes, flags);
+ final Locale locale = res.getConfiguration().getLocales().get(0);
+ final NumberFormat numberFormatter = getNumberFormatter(locale, rounded.fractionDigits);
+ final String formattedNumber = numberFormatter.format(rounded.value);
+ final String units;
+ if (rounded.units == MeasureUnit.BYTE) {
+ // ICU spells out "byte" instead of "B".
+ units = getByteSuffixOverride(res);
+ } else {
+ // Since ICU does not give us access to the pattern, we need to extract the unit string
+ // from ICU, which we do by taking out the formatted number out of the formatted string
+ // and trimming the result of spaces and controls.
+ final String formattedMeasure = formatMeasureShort(
+ locale, numberFormatter, rounded.value, rounded.units);
+ final String numberRemoved = deleteFirstFromString(formattedMeasure, formattedNumber);
+ units = SPACES_AND_CONTROLS.trim(numberRemoved).toString();
+ }
+ return new BytesResult(formattedNumber, units, rounded.roundedBytes);
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 24ded932b636..f901d43da60f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -83,6 +83,14 @@ public class FeatureFlagUtils {
public static final String SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE =
"settings_hide_second_layer_page_navigate_up_button_in_two_pane";
+ /** @hide */
+ public static final String SETTINGS_AUTO_TEXT_WRAPPING = "settings_auto_text_wrapping";
+
+ /** Flag to enable/disable guest mode UX changes as mentioned in b/214031645
+ * @hide
+ */
+ public static final String SETTINGS_GUEST_MODE_UX_CHANGES = "settings_guest_mode_ux_changes";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -110,6 +118,8 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true");
DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
+ DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
+ DEFAULT_FLAGS.put(SETTINGS_GUEST_MODE_UX_CHANGES, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -121,6 +131,7 @@ public class FeatureFlagUtils {
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE);
+ PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
}
/**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 52d222b19b6a..21c615c26879 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -574,7 +574,8 @@ public final class Display {
* @see com.android.service.display.DisplayDevice#hasStableUniqueId().
* @hide
*/
- public String getUniqueId() {
+ @TestApi
+ public @Nullable String getUniqueId() {
return mDisplayInfo.uniqueId;
}
@@ -1600,6 +1601,21 @@ public final class Display {
}
/**
+ * Returns the committed state of the display.
+ *
+ * @return The latest committed display state, such as {@link #STATE_ON}. The display state
+ * {@link Display#getState()} is set as committed only after power state changes finish.
+ *
+ * @hide
+ */
+ public int getCommittedState() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ return mIsValid ? mDisplayInfo.committedState : STATE_UNKNOWN;
+ }
+ }
+
+ /**
* Returns true if the specified UID has access to this display.
* @hide
*/
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 12ce8ee5e0ad..f65a69a8e2bc 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -253,6 +253,12 @@ public final class DisplayInfo implements Parcelable {
public int state;
/**
+ * The current committed state of the display. For example, this becomes
+ * {@link android.view.Display#STATE_ON} only after the power state ON is fully committed.
+ */
+ public int committedState;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -380,6 +386,7 @@ public final class DisplayInfo implements Parcelable {
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
&& presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state
+ && committedState == other.committedState
&& ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName)
&& removeMode == other.removeMode
@@ -431,6 +438,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos;
state = other.state;
+ committedState = other.committedState;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
removeMode = other.removeMode;
@@ -482,6 +490,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = source.readLong();
presentationDeadlineNanos = source.readLong();
state = source.readInt();
+ committedState = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString8();
uniqueId = source.readString8();
@@ -538,6 +547,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeLong(appVsyncOffsetNanos);
dest.writeLong(presentationDeadlineNanos);
dest.writeInt(state);
+ dest.writeInt(committedState);
dest.writeInt(ownerUid);
dest.writeString8(ownerPackageName);
dest.writeString8(uniqueId);
@@ -761,6 +771,8 @@ public final class DisplayInfo implements Parcelable {
sb.append(rotation);
sb.append(", state ");
sb.append(Display.stateToString(state));
+ sb.append(", committedState ");
+ sb.append(Display.stateToString(committedState));
if (Process.myUid() != Process.SYSTEM_UID) {
sb.append("}");
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 61098d60566f..7f8f50b7768e 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -50,29 +50,19 @@ import java.util.List;
*/
public class HandwritingInitiator {
/**
- * The touchSlop from {@link ViewConfiguration} used to decide whether a pointer is considered
- * moving or stationary.
+ * The maximum amount of distance a stylus touch can wander before it is considered
+ * handwriting.
*/
- private final int mTouchSlop;
+ private final int mHandwritingSlop;
/**
* The timeout used to distinguish tap or long click from handwriting. If the stylus doesn't
* move before this timeout, it's not considered as handwriting.
*/
private final long mHandwritingTimeoutInMillis;
- private State mState = new State();
+ private final State mState = new State();
private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
- /**
- * Helper method to reset the internal state of this class.
- * Calling this method will also prevent the following MotionEvents
- * triggers handwriting until the next stylus ACTION_DOWN/ACTION_POINTER_DOWN
- * arrives.
- */
- private void reset() {
- mState = new State();
- }
-
/** The reference to the View that currently has the input connection. */
@Nullable
@VisibleForTesting
@@ -89,7 +79,7 @@ public class HandwritingInitiator {
@VisibleForTesting
public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
@NonNull InputMethodManager inputMethodManager) {
- mTouchSlop = viewConfiguration.getScaledTouchSlop();
+ mHandwritingSlop = viewConfiguration.getScaledHandwritingSlop();
mHandwritingTimeoutInMillis = ViewConfiguration.getLongPressTimeout();
mImm = inputMethodManager;
}
@@ -120,8 +110,10 @@ public class HandwritingInitiator {
mState.mStylusDownTimeInMillis = motionEvent.getEventTime();
mState.mStylusDownX = motionEvent.getX(actionIndex);
mState.mStylusDownY = motionEvent.getY(actionIndex);
+ mState.mStylusDownCandidateView = new WeakReference<>(
+ findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY));
mState.mShouldInitHandwriting = true;
- mState.mExceedTouchSlop = false;
+ mState.mExceedHandwritingSlop = false;
break;
case MotionEvent.ACTION_POINTER_UP:
final int pointerId = motionEvent.getPointerId(motionEvent.getActionIndex());
@@ -134,19 +126,19 @@ public class HandwritingInitiator {
case MotionEvent.ACTION_UP:
// If it's ACTION_CANCEL or ACTION_UP, all the pointers go up. There is no need to
// check whether the stylus we are tracking goes up.
- reset();
+ mState.mShouldInitHandwriting = false;
break;
case MotionEvent.ACTION_MOVE:
// Either we've already tried to initiate handwriting, or the ongoing MotionEvent
// sequence is considered to be tap, long-click or other gestures.
- if (!mState.mShouldInitHandwriting || mState.mExceedTouchSlop) {
+ if (!mState.mShouldInitHandwriting || mState.mExceedHandwritingSlop) {
return;
}
final long timeElapsed =
motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
if (timeElapsed > mHandwritingTimeoutInMillis) {
- reset();
+ mState.mShouldInitHandwriting = false;
return;
}
@@ -154,9 +146,14 @@ public class HandwritingInitiator {
final float x = motionEvent.getX(pointerIndex);
final float y = motionEvent.getY(pointerIndex);
if (largerThanTouchSlop(x, y, mState.mStylusDownX, mState.mStylusDownY)) {
- mState.mExceedTouchSlop = true;
- View candidateView =
- findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY);
+ mState.mExceedHandwritingSlop = true;
+ View candidateView = mState.mStylusDownCandidateView.get();
+ if (candidateView == null || !candidateView.isAttachedToWindow()) {
+ // If there was no candidate view found in the stylus down event, or if that
+ // candidate view is no longer attached, search again for a candidate view.
+ candidateView = findBestCandidateView(mState.mStylusDownX,
+ mState.mStylusDownY);
+ }
if (candidateView != null) {
if (candidateView == getConnectedView()) {
startHandwriting(candidateView);
@@ -236,7 +233,7 @@ public class HandwritingInitiator {
* next ACTION_DOWN.
*/
private void tryStartHandwriting() {
- if (!mState.mExceedTouchSlop) {
+ if (!mState.mExceedHandwritingSlop) {
return;
}
final View connectedView = getConnectedView();
@@ -250,10 +247,11 @@ public class HandwritingInitiator {
}
final Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
+ if (isInHandwritingArea(handwritingArea, mState.mStylusDownX,
+ mState.mStylusDownY, connectedView)) {
startHandwriting(connectedView);
} else {
- reset();
+ mState.mShouldInitHandwriting = false;
}
}
@@ -261,7 +259,7 @@ public class HandwritingInitiator {
@VisibleForTesting
public void startHandwriting(@NonNull View view) {
mImm.startStylusHandwriting(view);
- reset();
+ mState.mShouldInitHandwriting = false;
}
/**
@@ -281,14 +279,21 @@ public class HandwritingInitiator {
*/
@Nullable
private View findBestCandidateView(float x, float y) {
+ float minDistance = Float.MAX_VALUE;
+ View bestCandidate = null;
+
// If the connectedView is not null and do not set any handwriting area, it will check
// whether the connectedView's boundary contains the initial stylus position. If true,
// directly return the connectedView.
final View connectedView = getConnectedView();
if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
- final Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (contains(handwritingArea, x, y)) {
- return connectedView;
+ Rect handwritingArea = getViewHandwritingArea(connectedView);
+ if (isInHandwritingArea(handwritingArea, x, y, connectedView)) {
+ final float distance = distance(handwritingArea, x, y);
+ if (distance == 0f) return connectedView;
+
+ bestCandidate = connectedView;
+ minDistance = distance;
}
}
@@ -297,18 +302,78 @@ public class HandwritingInitiator {
mHandwritingAreasTracker.computeViewInfos();
for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
final View view = viewInfo.getView();
- if (!view.isAutoHandwritingEnabled()) continue;
- if (contains(viewInfo.getHandwritingArea(), x, y)) {
- return viewInfo.getView();
+ final Rect handwritingArea = viewInfo.getHandwritingArea();
+ if (!isInHandwritingArea(handwritingArea, x, y, view)) continue;
+
+ final float distance = distance(handwritingArea, x, y);
+
+ if (distance == 0f) return view;
+ if (distance < minDistance) {
+ minDistance = distance;
+ bestCandidate = view;
}
}
- return null;
+ return bestCandidate;
+ }
+
+ /**
+ * Return the square of the distance from point (x, y) to the given rect, which is mainly used
+ * for comparison. The distance is defined to be: the shortest distance between (x, y) to any
+ * point on rect. When (x, y) is contained by the rect, return 0f.
+ */
+ private static float distance(@NonNull Rect rect, float x, float y) {
+ if (contains(rect, x, y, 0f, 0f, 0f, 0f)) {
+ return 0f;
+ }
+
+ /* The distance between point (x, y) and rect, there are 2 basic cases:
+ * a) The distance is the distance from (x, y) to the closest corner on rect.
+ * o | |
+ * ---+-----+---
+ * | |
+ * ---+-----+---
+ * | |
+ * b) The distance is the distance from (x, y) to the closest edge on rect.
+ * | o |
+ * ---+-----+---
+ * | |
+ * ---+-----+---
+ * | |
+ * We define xDistance as following(similar for yDistance):
+ * If x is in [left, right) 0, else min(abs(x - left), abs(x - y))
+ * For case a, sqrt(xDistance^2 + yDistance^2) is the final distance.
+ * For case b, distance should be yDistance, which is also equal to
+ * sqrt(xDistance^2 + yDistance^2) because xDistance is 0.
+ */
+ final float xDistance;
+ if (x >= rect.left && x < rect.right) {
+ xDistance = 0f;
+ } else if (x < rect.left) {
+ xDistance = rect.left - x;
+ } else {
+ xDistance = x - rect.right;
+ }
+
+ final float yDistance;
+ if (y >= rect.top && y < rect.bottom) {
+ yDistance = 0f;
+ } else if (y < rect.top) {
+ yDistance = rect.top - y;
+ } else {
+ yDistance = y - rect.bottom;
+ }
+ // We can omit sqrt here because we only need the distance for comparison.
+ return xDistance * xDistance + yDistance * yDistance;
}
/**
* Return the handwriting area of the given view, represented in the window's coordinate.
* If the view didn't set any handwriting area, it will return the view's boundary.
* It will return null if the view or its handwriting area is not visible.
+ *
+ * The handwriting area is clipped to its visible part.
+ * Notice that the returned rectangle is the view's original handwriting area without the
+ * view's handwriting area extends.
*/
@Nullable
private static Rect getViewHandwritingArea(@NonNull View view) {
@@ -329,17 +394,34 @@ public class HandwritingInitiator {
}
/**
- * Return true if the (x, y) is inside by the given {@link Rect}.
+ * Return true if the (x, y) is inside by the given {@link Rect} with the View's
+ * handwriting bounds with offsets applied.
*/
- private boolean contains(@Nullable Rect rect, float x, float y) {
- if (rect == null) return false;
- return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
+ private boolean isInHandwritingArea(@Nullable Rect handwritingArea,
+ float x, float y, View view) {
+ if (handwritingArea == null) return false;
+
+ return contains(handwritingArea, x, y,
+ view.getHandwritingBoundsOffsetLeft(),
+ view.getHandwritingBoundsOffsetTop(),
+ view.getHandwritingBoundsOffsetRight(),
+ view.getHandwritingBoundsOffsetBottom());
+ }
+
+ /**
+ * Return true if the (x, y) is inside by the given {@link Rect} offset by the given
+ * offsetLeft, offsetTop, offsetRight and offsetBottom.
+ */
+ private static boolean contains(@NonNull Rect rect, float x, float y,
+ float offsetLeft, float offsetTop, float offsetRight, float offsetBottom) {
+ return x >= rect.left - offsetLeft && x < rect.right + offsetRight
+ && y >= rect.top - offsetTop && y < rect.bottom + offsetBottom;
}
private boolean largerThanTouchSlop(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
- return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
+ return dx * dx + dy * dy > mHandwritingSlop * mHandwritingSlop;
}
/** Object that keeps the MotionEvent related states for HandwritingInitiator. */
@@ -358,11 +440,12 @@ public class HandwritingInitiator {
*/
private boolean mShouldInitHandwriting = false;
/**
- * Whether the current ongoing stylus MotionEvent sequence already exceeds the touchSlop.
- * It's used for the case where the stylus exceeds touchSlop before the target View built
- * InputConnection.
+ * Whether the current ongoing stylus MotionEvent sequence already exceeds the
+ * handwriting slop.
+ * It's used for the case where the stylus exceeds handwriting slop before the target View
+ * built InputConnection.
*/
- private boolean mExceedTouchSlop = false;
+ private boolean mExceedHandwritingSlop = false;
/** The pointer id of the stylus pointer that is being tracked. */
private int mStylusPointerId = -1;
@@ -371,6 +454,12 @@ public class HandwritingInitiator {
/** The initial location where the stylus pointer goes down. */
private float mStylusDownX = Float.NaN;
private float mStylusDownY = Float.NaN;
+ /**
+ * The best candidate view to initialize handwriting mode based on the initial location
+ * where the stylus pointer goes down, or null if the location was not within any candidate
+ * view's handwriting area.
+ */
+ private WeakReference<View> mStylusDownCandidateView = new WeakReference<>(null);
}
/** The helper method to check if the given view is still active for handwriting. */
diff --git a/core/java/android/view/IDisplayWindowRotationCallback.aidl b/core/java/android/view/IDisplayChangeWindowCallback.aidl
index 1ffe2dde40f1..00a5b7b831ca 100644
--- a/core/java/android/view/IDisplayWindowRotationCallback.aidl
+++ b/core/java/android/view/IDisplayChangeWindowCallback.aidl
@@ -17,13 +17,15 @@
package android.view;
import android.window.WindowContainerTransaction;
+import android.window.DisplayAreaInfo;
/**
- * Interface to be invoked by the controller when it has finished preparing for a display rotation.
+ * Interface to be invoked by the controller when it has finished preparing for a display
+ * size change.
*
- * @see IDisplayWindowRotationController
+ * @see IDisplayChangeWindowController
* @hide
*/
-interface IDisplayWindowRotationCallback {
- void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
+interface IDisplayChangeWindowCallback {
+ void continueDisplayChange(in WindowContainerTransaction t);
}
diff --git a/core/java/android/view/IDisplayWindowRotationController.aidl b/core/java/android/view/IDisplayChangeWindowController.aidl
index c1c7464c3168..8c0bb6a54528 100644
--- a/core/java/android/view/IDisplayWindowRotationController.aidl
+++ b/core/java/android/view/IDisplayChangeWindowController.aidl
@@ -16,11 +16,12 @@
package android.view;
-import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayChangeWindowCallback;
+import android.window.DisplayAreaInfo;
/**
- * Singular controller of a "remote" display rotation. When a display rotation is started, WM
- * freezes the screen. It will then call into this controller and wait for a response via the
+ * Singular controller of a "remote" display change. When a display rotation or change is started,
+ * WM freezes the screen. It will then call into this controller and wait for a response via the
* callback.
*
* This needs to provide configuration changes because those changes need to be applied in sync
@@ -36,17 +37,18 @@ import android.view.IDisplayWindowRotationCallback;
*
* @hide
*/
-oneway interface IDisplayWindowRotationController {
+oneway interface IDisplayChangeWindowController {
/**
- * Called when WM needs to know how to update tasks in response to a display rotation.
- * If this isn't called, a timeout will continue the rotation in WM.
+ * Called when WM needs to know how to update tasks in response to a display change.
+ * If this isn't called, a timeout will continue the change in WM.
*
- * @param displayId the display that is rotating.
- * @param fromRotation the rotation the display is rotating from.
- * @param toRotation the rotation the display is rotating to.
+ * @param fromRotation the old rotation
+ * @param newRotation the new rotation
+ * @param newDisplayAreaInfo the new display area info after the change
* @param callback A callback to be called when this has calculated updated configs.
*/
- void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- in IDisplayWindowRotationCallback callback);
+ void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ in DisplayAreaInfo newDisplayAreaInfo, in IDisplayChangeWindowCallback callback);
+
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index fb562d8e97db..acdff4fb52fd 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -39,7 +39,7 @@ import android.view.ICrossWindowBlurEnabledListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowController;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedTaskListener;
import android.view.IScrollCaptureResponseListener;
@@ -145,7 +145,7 @@ interface IWindowManager
* controller is called after the display has "frozen" for a rotation and display rotation will
* only continue once the controller has finished calculating associated configurations.
*/
- void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
+ void setDisplayChangeWindowController(IDisplayChangeWindowController controller);
/**
* Adds a root container that a client shell can populate with its own windows (usually via
@@ -250,18 +250,6 @@ interface IWindowManager
*/
void refreshScreenCaptureDisabled();
- // These can only be called with the SET_ORIENTATION permission.
- /**
- * Update the current screen rotation based on the current state of
- * the world.
- * @param alwaysSendConfiguration Flag to force a new configuration to
- * be evaluated. This can be used when there are other parameters in
- * configuration that are changing.
- * @param forceRelayout If true, the window manager will always do a relayout
- * of its windows even if the rotation hasn't changed.
- */
- void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout);
-
/**
* Retrieve the current orientation of the primary screen.
* @return Constant as per {@link android.view.Surface.Rotation}.
@@ -442,11 +430,6 @@ interface IWindowManager
boolean isSafeModeEnabled();
/**
- * Enables the screen if all conditions are met.
- */
- void enableScreenIfNeeded();
-
- /**
* Clears the frame statistics for a given window.
*
* @param token The window token.
@@ -560,6 +543,21 @@ interface IWindowManager
boolean isWindowTraceEnabled();
/**
+ * Starts a transition trace.
+ */
+ void startTransitionTrace();
+
+ /**
+ * Stops a transition trace.
+ */
+ void stopTransitionTrace();
+
+ /**
+ * Returns true if transition trace is enabled.
+ */
+ boolean isTransitionTraceEnabled();
+
+ /**
* Gets the windowing mode of the display.
*
* @param displayId The id of the display.
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7d5603994efa..addbab07c478 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -517,6 +518,7 @@ public final class InputDevice implements Parcelable {
* @param id The device id.
* @return The input device or null if not found.
*/
+ @Nullable
public static InputDevice getDevice(int id) {
return InputManager.getInstance().getInputDevice(id);
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index f7bca5bfe188..d75ff2fc7dc2 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -29,8 +29,6 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.window.WindowTokenClient;
-import android.view.InsetsState;
-import android.view.WindowManagerGlobal;
import android.view.accessibility.IAccessibilityEmbeddedConnection;
import java.util.Objects;
@@ -280,7 +278,7 @@ public class SurfaceControlViewHost {
public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
@NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
mWm = wwm;
- mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer);
+ mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout(), useSfChoreographer);
addConfigCallback(c, d);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
@@ -310,7 +308,7 @@ public class SurfaceControlViewHost {
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
- mViewRoot = new ViewRootImpl(context, display, mWm);
+ mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout());
addConfigCallback(context, display);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 2b79bbfa72d4..2d4da2c88ce8 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -18,8 +18,8 @@ package android.view;
import android.annotation.IntDef;
import android.compat.annotation.UnsupportedAppUsage;
+import android.hardware.input.InputManager;
import android.os.Build;
-import android.sysprop.InputProperties;
import android.util.ArrayMap;
import android.util.Pools.SynchronizedPool;
@@ -278,8 +278,8 @@ public final class VelocityTracker {
private VelocityTracker(@VelocityTrackerStrategy int strategy) {
// If user has not selected a specific strategy
if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) {
+ final String strategyProperty = InputManager.getInstance().getVelocityTrackerStrategy();
// Check if user specified strategy by overriding system property.
- String strategyProperty = InputProperties.velocitytracker_strategy().orElse(null);
if (strategyProperty == null || strategyProperty.isEmpty()) {
mStrategy = strategy;
} else {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ba6ba63e4ed0..f15dc16e4c5e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4475,6 +4475,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected int mPaddingBottom;
/**
+ * The amount of pixel offset applied to the left edge of this view's handwriting bounds.
+ */
+ private float mHandwritingBoundsOffsetLeft;
+
+ /**
+ * The amount of pixel offset applied to the top edge of this view's handwriting bounds.
+ */
+ private float mHandwritingBoundsOffsetTop;
+
+ /**
+ * The amount of pixel offset applied to the right edge of this view's handwriting bounds.
+ */
+ private float mHandwritingBoundsOffsetRight;
+
+ /**
+ * The amount of pixel offset applied to the bottom edge of this view's handwriting bounds.
+ */
+ private float mHandwritingBoundsOffsetBottom;
+
+ /**
* The layout insets in pixels, that is the distance in pixels between the
* visible edges of this view its bounds.
*/
@@ -6078,6 +6098,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case R.styleable.View_autoHandwritingEnabled:
setAutoHandwritingEnabled(a.getBoolean(attr, true));
break;
+ case R.styleable.View_handwritingBoundsOffsetLeft:
+ mHandwritingBoundsOffsetLeft = a.getDimension(attr, 0);
+ break;
+ case R.styleable.View_handwritingBoundsOffsetTop:
+ mHandwritingBoundsOffsetTop = a.getDimension(attr, 0);
+ break;
+ case R.styleable.View_handwritingBoundsOffsetRight:
+ mHandwritingBoundsOffsetRight = a.getDimension(attr, 0);
+ break;
+ case R.styleable.View_handwritingBoundsOffsetBottom:
+ mHandwritingBoundsOffsetBottom = a.getDimension(attr, 0);
+ break;
}
}
@@ -12006,12 +12038,91 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Set a list of handwriting areas in this view. If there is any stylus {@link MotionEvent}
- * occurs within those areas, it will trigger stylus handwriting mode. This can be disabled by
+ * Set the amount of offset applied to this view's stylus handwriting bounds. A positive offset
+ * will offset the edge outwards.The base handwriting bounds of a view is its visible bounds.
+ * The handwriting bounds offsets are applied to the base handwriting bounds to determine the
+ * final handwriting bounds.
+ * <p> This method is mainly used to enlarge the view's handwriting bounds for a better user
+ * experience.
+ * <p> Note that when the view is clipped (e.g. the view is in a
+ * {@link android.widget.ScrollView}), the offsets are applied after the view's handwriting
+ * bounds is clipped.
+ *
+ * @param offsetLeft the amount of pixel offset applied to the left edge outwards of the view's
+ * handwriting bounds.
+ * @param offsetTop the amount of pixel offset applied to the top edge outwards of the view's
+ * handwriting bounds.
+ * @param offsetRight the amount of pixel offset applied to the right edge outwards of the
+ * view's handwriting bounds.
+ * @param offsetBottom the amount of pixel offset applied to the bottom edge outwards of the
+ * view's handwriting bounds.
+ *
+ * @see #setAutoHandwritingEnabled(boolean)
+ * @see #getHandwritingBoundsOffsetLeft()
+ * @see #getHandwritingBoundsOffsetTop()
+ * @see #getHandwritingBoundsOffsetRight()
+ * @see #getHandwritingBoundsOffsetBottom()
+ */
+ public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop,
+ float offsetRight, float offsetBottom) {
+ mHandwritingBoundsOffsetLeft = offsetLeft;
+ mHandwritingBoundsOffsetTop = offsetTop;
+ mHandwritingBoundsOffsetRight = offsetRight;
+ mHandwritingBoundsOffsetBottom = offsetBottom;
+ }
+
+ /**
+ * Return the amount of offset applied to the left edge of this view's handwriting bounds,
+ * in the unit of pixel.
+ *
+ * @see #setAutoHandwritingEnabled(boolean)
+ * @see #setHandwritingBoundsOffsets(float, float, float, float)
+ */
+ public float getHandwritingBoundsOffsetLeft() {
+ return mHandwritingBoundsOffsetLeft;
+ }
+
+ /**
+ * Return the amount of offset applied to the top edge of this view's handwriting bounds,
+ * in the unit of pixel.
+ *
+ * @see #setAutoHandwritingEnabled(boolean)
+ * @see #setHandwritingBoundsOffsets(float, float, float, float)
+ */
+ public float getHandwritingBoundsOffsetTop() {
+ return mHandwritingBoundsOffsetTop;
+ }
+
+ /**
+ * Return the amount of offset applied to the right edge of this view's handwriting bounds, in
+ * the unit of pixel.
+ *
+ * @see #setAutoHandwritingEnabled(boolean)
+ * @see #setHandwritingBoundsOffsets(float, float, float, float)
+ */
+ public float getHandwritingBoundsOffsetRight() {
+ return mHandwritingBoundsOffsetRight;
+ }
+
+ /**
+ * Return the amount of offset applied to the bottom edge of this view's handwriting bounds, in
+ * the unit of pixel.
+ *
+ * @see #setAutoHandwritingEnabled(boolean)
+ * @see #setHandwritingBoundsOffsets(float, float, float, float)
+ */
+ public float getHandwritingBoundsOffsetBottom() {
+ return mHandwritingBoundsOffsetBottom;
+ }
+
+
+ /**
+ * Set a handwriting area in this view. If there is any stylus {@link MotionEvent}
+ * occurs within this area, it will trigger stylus handwriting mode. This can be disabled by
* disabling the auto handwriting initiation by calling
* {@link #setAutoHandwritingEnabled(boolean)} with false.
*
- * @attr rects a list of handwriting area in the view's local coordiniates.
+ * @attr rect the handwriting area in the view's local coordiniates.
*
* @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)
* @see #setAutoHandwritingEnabled(boolean)
@@ -23904,6 +24015,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
rebuildOutline();
+ if (onCheckIsTextEditor()) {
+ setHandwritingArea(new Rect(0, 0, newWidth, newHeight));
+ }
}
/**
@@ -31500,6 +31614,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} when there
* is stylus movement detected.
*
+ * Note that this attribute has no effect on the View's children. For example, if a
+ * {@link ViewGroup} disables auto handwriting but its children set auto handwriting to true,
+ * auto handwriting will still work for the children, and vice versa.
+ *
* @see #onCreateInputConnection(EditorInfo)
* @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)
* @param enabled whether auto handwriting initiation is enabled for this view.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 638b8f9f9b40..e5a535b59eb6 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -178,6 +178,9 @@ public class ViewConfiguration {
*/
private static final int TOUCH_SLOP = 8;
+ /** Distance a stylus touch can wander before we think the user is handwriting in dips. */
+ private static final int HANDWRITING_SLOP = 4;
+
/**
* Defines the minimum size of the touch target for a scrollbar in dips
*/
@@ -327,6 +330,7 @@ public class ViewConfiguration {
private final int mMaximumFlingVelocity;
private final int mScrollbarSize;
private final int mTouchSlop;
+ private final int mHandwritingSlop;
private final int mMinScalingSpan;
private final int mHoverSlop;
private final int mMinScrollbarTouchTarget;
@@ -370,6 +374,7 @@ public class ViewConfiguration {
mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
mScrollbarSize = SCROLL_BAR_SIZE;
mTouchSlop = TOUCH_SLOP;
+ mHandwritingSlop = HANDWRITING_SLOP;
mHoverSlop = TOUCH_SLOP / 2;
mMinScrollbarTouchTarget = MIN_SCROLLBAR_TOUCH_TARGET;
mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
@@ -475,6 +480,8 @@ public class ViewConfiguration {
com.android.internal.R.bool.config_ui_enableFadingMarquee);
mTouchSlop = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
+ mHandwritingSlop = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_viewConfigurationHandwritingSlop);
mHoverSlop = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_viewConfigurationHoverSlop);
mMinScrollbarTouchTarget = res.getDimensionPixelSize(
@@ -734,6 +741,14 @@ public class ViewConfiguration {
}
/**
+ * @return Distance in pixels a stylus touch can wander before we think the user is
+ * handwriting.
+ */
+ public int getScaledHandwritingSlop() {
+ return mHandwritingSlop;
+ }
+
+ /**
* @return Distance in pixels a hover can wander while it is still considered "stationary".
*
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 127c7b7a8dc9..2dbf42f93e62 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -90,6 +90,7 @@ import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodCl
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import android.Manifest;
+import android.animation.AnimationHandler;
import android.animation.LayoutTransition;
import android.annotation.AnyThread;
import android.annotation.NonNull;
@@ -563,7 +564,7 @@ public final class ViewRootImpl implements ViewParent,
private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
private final Rect mTempRect = new Rect();
- private final WindowLayout mWindowLayout = new WindowLayout();
+ private final WindowLayout mWindowLayout;
private ViewRootImpl mParentViewRoot;
@@ -603,6 +604,7 @@ public final class ViewRootImpl implements ViewParent,
int mSyncSeqId = 0;
int mLastSyncSeqId = 0;
+ private boolean mUpdateSurfaceNeeded;
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
boolean mForceNextWindowRelayout;
@@ -880,18 +882,20 @@ public final class ViewRootImpl implements ViewParent,
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
- this(context, display, WindowManagerGlobal.getWindowSession(),
+ this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout(),
false /* useSfChoreographer */);
}
- public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
- this(context, display, session, false /* useSfChoreographer */);
+ public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
+ WindowLayout windowLayout) {
+ this(context, display, session, windowLayout, false /* useSfChoreographer */);
}
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
- boolean useSfChoreographer) {
+ WindowLayout windowLayout, boolean useSfChoreographer) {
mContext = context;
mWindowSession = session;
+ mWindowLayout = windowLayout;
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
@@ -924,7 +928,8 @@ public final class ViewRootImpl implements ViewParent,
? Choreographer.getSfInstance() : Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
- mHandwritingInitiator = new HandwritingInitiator(mViewConfiguration,
+ mHandwritingInitiator = new HandwritingInitiator(
+ mViewConfiguration,
mContext.getSystemService(InputMethodManager.class));
String processorOverrideName = context.getResources().getString(
@@ -1363,6 +1368,8 @@ public final class ViewRootImpl implements ViewParent,
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
+
+ AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
}
}
}
@@ -1708,6 +1715,7 @@ public final class ViewRootImpl implements ViewParent,
if (!mAppVisible) {
WindowManagerGlobal.trimForeground();
}
+ AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
}
}
@@ -1767,7 +1775,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- mForceNextWindowRelayout = forceNextWindowRelayout;
+ mForceNextWindowRelayout |= forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
@@ -2893,7 +2901,6 @@ public final class ViewRootImpl implements ViewParent,
final int surfaceGenerationId = mSurface.getGenerationId();
final boolean isViewVisible = viewVisibility == View.VISIBLE;
- final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
boolean surfaceSizeChanged = false;
boolean surfaceCreated = false;
boolean surfaceDestroyed = false;
@@ -2997,6 +3004,8 @@ public final class ViewRootImpl implements ViewParent,
!mFirst, INVALID_DISPLAY /* same display */);
updatedConfiguration = true;
}
+ final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
+ mUpdateSurfaceNeeded = false;
surfaceSizeChanged = false;
if (!mLastSurfaceSize.equals(mSurfaceSize)) {
@@ -3075,8 +3084,7 @@ public final class ViewRootImpl implements ViewParent,
if (isHardwareEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- } else if ((surfaceReplaced
- || surfaceSizeChanged || windowRelayoutWasForced)
+ } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
&& mSurfaceHolder == null
&& mAttachInfo.mThreadedRenderer != null
&& mSurface.isValid()) {
@@ -5204,6 +5212,21 @@ public final class ViewRootImpl implements ViewParent,
throw new IllegalArgumentException("No merged config provided.");
}
+ final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration()
+ .windowConfiguration.getRotation();
+ final int newRotation = mergedConfiguration.getMergedConfiguration()
+ .windowConfiguration.getRotation();
+ if (lastRotation != newRotation) {
+ // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change.
+ // Because even if the actual surface size is not changed, e.g. flip 180 degrees,
+ // the buffers may still have content in previous rotation. And the next draw may
+ // not update all regions, that causes some afterimages to flicker.
+ mUpdateSurfaceNeeded = true;
+ if (!mIsInTraversal) {
+ mForceNextWindowRelayout = true;
+ }
+ }
+
Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
if (DEBUG_CONFIGURATION) Log.v(mTag,
@@ -8477,6 +8500,7 @@ public final class ViewRootImpl implements ViewParent,
mInsetsController.onControlsChanged(null);
mAdded = false;
+ AnimationHandler.removeRequestor(this);
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 00052f6015d5..bf9767ccb9d8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -341,6 +341,18 @@ public interface WindowManager extends ViewManager {
int TRANSIT_OLD_TASK_FRAGMENT_CHANGE = 30;
/**
+ * A dream activity is being opened.
+ * @hide
+ */
+ int TRANSIT_OLD_DREAM_ACTIVITY_OPEN = 31;
+
+ /**
+ * A dream activity is being closed.
+ * @hide
+ */
+ int TRANSIT_OLD_DREAM_ACTIVITY_CLOSE = 32;
+
+ /**
* @hide
*/
@IntDef(prefix = { "TRANSIT_OLD_" }, value = {
@@ -368,7 +380,9 @@ public interface WindowManager extends ViewManager {
TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
TRANSIT_OLD_TASK_FRAGMENT_OPEN,
TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
- TRANSIT_OLD_TASK_FRAGMENT_CHANGE
+ TRANSIT_OLD_TASK_FRAGMENT_CHANGE,
+ TRANSIT_OLD_DREAM_ACTIVITY_OPEN,
+ TRANSIT_OLD_DREAM_ACTIVITY_CLOSE
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionOldType {}
@@ -1963,6 +1977,13 @@ public interface WindowManager extends ViewManager {
* {@link android.R.style#Theme_Holo_Wallpaper_NoTitleBar},
* {@link android.R.style#Theme_DeviceDefault_Wallpaper}, and
* {@link android.R.style#Theme_DeviceDefault_Wallpaper_NoTitleBar}.</p>
+ *
+ * <p> When this flag is set, all touch events sent to this window is also sent to the
+ * wallpaper, which is used to interact with live wallpapers. Check
+ * {@link LayoutParams#areWallpaperTouchEventsEnabled()}, which is set to {@code true}
+ * by default. When showing sensitive information on the window, if you want to disable
+ * sending the touch events to the wallpaper, use
+ * {@link LayoutParams#setWallpaperTouchEventsEnabled(boolean)}.</p>
*/
public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
@@ -3638,6 +3659,15 @@ public interface WindowManager extends ViewManager {
public LayoutParams[] paramsForRotation;
/**
+ * Specifies whether to send touch events to wallpaper, if the window shows wallpaper in the
+ * background. By default, this is set to {@code true} i.e. if any window shows wallpaper
+ * in the background, the wallpaper will receive touch events, unless specified otherwise.
+ *
+ * @see android.view.WindowManager.LayoutParams#FLAG_SHOW_WALLPAPER
+ */
+ private boolean mWallpaperTouchEventsEnabled = true;
+
+ /**
* Specifies types of insets that this window should avoid overlapping during layout.
*
* @param types which {@link WindowInsets.Type}s of insets that this window should avoid.
@@ -3715,6 +3745,31 @@ public interface WindowManager extends ViewManager {
}
/**
+ * Set whether sending touch events to the system wallpaper (which can be provided by a
+ * third-party application) should be enabled for windows that show wallpaper in
+ * background. By default, this is set to {@code true}.
+ * Check {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WALLPAPER} for more
+ * information on showing system wallpaper behind the window.
+ *
+ * @param enable whether to enable sending touch events to the system wallpaper.
+ */
+ public void setWallpaperTouchEventsEnabled(boolean enable) {
+ mWallpaperTouchEventsEnabled = enable;
+ }
+
+ /**
+ * Returns whether sending touch events to the system wallpaper (which can be provided by a
+ * third-party application) is enabled for windows that show wallpaper in background.
+ * Check {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WALLPAPER} for more
+ * information on showing system wallpaper behind the window.
+ *
+ * @return whether sending touch events to the system wallpaper is enabled.
+ */
+ public boolean areWallpaperTouchEventsEnabled() {
+ return mWallpaperTouchEventsEnabled;
+ }
+
+ /**
* @return the {@link WindowInsets.Type}s that this window is avoiding overlapping.
*/
public @InsetsType int getFitInsetsTypes() {
@@ -4022,6 +4077,7 @@ public interface WindowManager extends ViewManager {
} else {
out.writeInt(0);
}
+ out.writeBoolean(mWallpaperTouchEventsEnabled);
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4109,6 +4165,7 @@ public interface WindowManager extends ViewManager {
paramsForRotation = new LayoutParams[paramsForRotationLength];
in.readTypedArray(paramsForRotation, LayoutParams.CREATOR);
}
+ mWallpaperTouchEventsEnabled = in.readBoolean();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4426,6 +4483,11 @@ public interface WindowManager extends ViewManager {
changes |= LAYOUT_CHANGED;
}
+ if (mWallpaperTouchEventsEnabled != o.mWallpaperTouchEventsEnabled) {
+ mWallpaperTouchEventsEnabled = o.mWallpaperTouchEventsEnabled;
+ changes |= LAYOUT_CHANGED;
+ }
+
return changes;
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index aae930edb729..85a5762f7f3d 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -386,7 +386,7 @@ public final class WindowManagerGlobal {
root = new ViewRootImpl(view.getContext(), display);
} else {
root = new ViewRootImpl(view.getContext(), display,
- windowlessSession);
+ windowlessSession, new WindowlessWindowLayout());
}
view.setLayoutParams(wparams);
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 4d07171d3086..43d427db2c75 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -237,10 +237,6 @@ public interface WindowManagerPolicyConstants {
*/
int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER - 1;
- // TODO(b/207185041): Remove this divider workaround after we full remove leagacy split and
- // make app pair split only have single root then we can just attach the
- // divider to the single root task in shell.
- int SPLIT_DIVIDER_LAYER = TYPE_LAYER_MULTIPLIER * 3;
int WATERMARK_LAYER = TYPE_LAYER_MULTIPLIER * 100;
int STRICT_MODE_LAYER = TYPE_LAYER_MULTIPLIER * 101;
int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
diff --git a/core/java/android/view/WindowlessWindowLayout.java b/core/java/android/view/WindowlessWindowLayout.java
new file mode 100644
index 000000000000..7cc50c579d0d
--- /dev/null
+++ b/core/java/android/view/WindowlessWindowLayout.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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 android.app.WindowConfiguration.WindowingMode;
+import android.graphics.Rect;
+import android.window.ClientWindowFrames;
+
+/**
+ * Computes window frames for the windowless window.
+ * @hide
+ */
+public class WindowlessWindowLayout extends WindowLayout {
+
+ @Override
+ public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
+ Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
+ int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
+ Rect attachedWindowFrame, float compatScale, ClientWindowFrames outFrames) {
+ outFrames.frame.set(0, 0, attrs.width, attrs.height);
+ outFrames.displayFrame.set(outFrames.frame);
+ outFrames.parentFrame.set(outFrames.frame);
+ }
+}
+
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a20b2b2f79a4..953f2615b539 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2659,8 +2659,8 @@ public class AccessibilityNodeInfo implements Parcelable {
* <p>
* A live region is a node that contains information that is important for
* the user and when it changes the user should be notified. For example,
- * in a login screen with a TextView that displays an "incorrect password"
- * notification, that view should be marked as a live region with mode
+ * a Snackbar that displays a confirmation notification should be marked
+ * as a live region with mode
* {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
* <p>
* It is the responsibility of the accessibility service to monitor
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 7d7270d1ef76..6a27eb5a5d82 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -27,6 +27,7 @@ import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -47,17 +48,22 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.metrics.LogMaker;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
+import android.service.autofill.IFillCallback;
import android.service.autofill.UserData;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -78,6 +84,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
@@ -102,6 +109,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import sun.misc.Cleaner;
@@ -171,6 +179,12 @@ import sun.misc.Cleaner;
* shows an autofill save UI if the value of savable views have changed. If the user selects the
* option to Save, the current value of the views is then sent to the autofill service.
*
+ * <p>There is another choice for the application to provide it's datasets to the Autofill framework
+ * by setting an {@link AutofillRequestCallback} through
+ * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
+ * its callback instead of the default {@link AutofillService}. See
+ * {@link AutofillRequestCallback} for more details.
+ *
* <h3 id="additional-notes">Additional notes</h3>
*
* <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -296,6 +310,7 @@ public final class AutofillManager {
/** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
/** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
/** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
+ /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
// NOTE: flag below is used by the session start receiver only, hence it can have values above
/** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -708,6 +723,11 @@ public final class AutofillManager {
@GuardedBy("mLock")
private boolean mEnabledForAugmentedAutofillOnly;
+ @GuardedBy("mLock")
+ @Nullable private AutofillRequestCallback mAutofillRequestCallback;
+ @GuardedBy("mLock")
+ @Nullable private Executor mRequestCallbackExecutor;
+
/**
* Indicates whether there is already a field to do a fill request after
* the activity started.
@@ -2042,6 +2062,32 @@ public final class AutofillManager {
return new AutofillId(parent.getAutofillViewId(), virtualId);
}
+ /**
+ * Sets the client's suggestions callback for autofill.
+ *
+ * @see AutofillRequestCallback
+ *
+ * @param executor specifies the thread upon which the callbacks will be invoked.
+ * @param callback which handles autofill request to provide client's suggestions.
+ */
+ public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AutofillRequestCallback callback) {
+ synchronized (mLock) {
+ mRequestCallbackExecutor = executor;
+ mAutofillRequestCallback = callback;
+ }
+ }
+
+ /**
+ * clears the client's suggestions callback for autofill.
+ */
+ public void clearAutofillRequestCallback() {
+ synchronized (mLock) {
+ mRequestCallbackExecutor = null;
+ mAutofillRequestCallback = null;
+ }
+ }
+
@GuardedBy("mLock")
private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
@NonNull AutofillValue value, int flags) {
@@ -2102,6 +2148,13 @@ public final class AutofillManager {
}
}
+ if (mAutofillRequestCallback != null) {
+ if (sDebug) {
+ Log.d(TAG, "startSession with the client suggestions provider");
+ }
+ flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
+ }
+
mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, clientActivity,
@@ -2454,6 +2507,28 @@ public final class AutofillManager {
}
}
+ private void onFillRequest(InlineSuggestionsRequest request,
+ CancellationSignal cancellationSignal, FillCallback callback) {
+ final AutofillRequestCallback autofillRequestCallback;
+ final Executor executor;
+ synchronized (mLock) {
+ autofillRequestCallback = mAutofillRequestCallback;
+ executor = mRequestCallbackExecutor;
+ }
+ if (autofillRequestCallback != null && executor != null) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ autofillRequestCallback.onFillRequest(
+ request, cancellationSignal, callback));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } else {
+ callback.onSuccess(null);
+ }
+ }
+
/** @hide */
public static final int SET_STATE_FLAG_ENABLED = 0x01;
/** @hide */
@@ -3943,6 +4018,23 @@ public final class AutofillManager {
}
}
+ @Override
+ public void requestFillFromClient(int id, InlineSuggestionsRequest request,
+ IFillCallback callback) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ ICancellationSignal transport = CancellationSignal.createTransport();
+ try {
+ callback.onCancellable(transport);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error requesting a cancellation", e);
+ }
+
+ afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
+ new FillCallback(callback, id));
+ }
+ }
+
public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
new file mode 100644
index 000000000000..e632a5849471
--- /dev/null
+++ b/core/java/android/view/autofill/AutofillRequestCallback.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.CancellationSignal;
+import android.service.autofill.FillCallback;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+/**
+ * <p>This class is used to provide some input suggestions to the Autofill framework.
+ *
+ * <P>When the user is requested to input something, Autofill will try to query input suggestions
+ * for the user choosing. If the application want to provide some internal input suggestions,
+ * implements this callback and register via
+ * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
+ * AutofillRequestCallback)}. Autofill will callback the
+ * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
+ * input suggestions.
+ *
+ * <P>To make sure the callback to take effect, must register before the autofill session starts.
+ * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
+ * session, and then the callback will be used at the next restarted session.
+ *
+ * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
+ * {@link AutofillId}s from its view structure. Below is an example:
+ * <pre class="prettyprint">
+ * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
+ * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
+ * </pre>
+ * To learn more about creating a {@link android.service.autofill.FillResponse}, read
+ * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
+ *
+ * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
+ * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
+ * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
+ * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
+ * client would like to keep no suggestions for the field, respond with an empty
+ * {@link android.service.autofill.FillResponse} which has no dataset.
+ *
+ * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
+ * the keyboard may choose to block your app from the inline strip.
+ */
+public interface AutofillRequestCallback {
+ /**
+ * Called by the Android system to decide if a screen can be autofilled by the callback.
+ *
+ * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
+ * currently inline suggestions are supported and can be displayed.
+ * @param cancellationSignal signal for observing cancellation requests. The system will use
+ * this to notify you that the fill result is no longer needed and you should stop
+ * handling this fill request in order to save resources.
+ * @param callback object used to notify the result of the request.
+ */
+ void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
+}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 51afe4cf784d..2e5967cc32d1 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,9 +24,11 @@ import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Rect;
import android.os.IBinder;
+import android.service.autofill.IFillCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.KeyEvent;
import com.android.internal.os.IResultReceiver;
@@ -142,6 +144,12 @@ oneway interface IAutoFillManagerClient {
void requestShowSoftInput(in AutofillId id);
/**
+ * Requests to determine if a screen can be autofilled by the client app.
+ */
+ void requestFillFromClient(int id, in InlineSuggestionsRequest request,
+ in IFillCallback callback);
+
+ /**
* Notifies autofill ids that require to show the fill dialog.
*/
void notifyFillDialogTriggerIds(in List<AutofillId> ids);
diff --git a/core/java/android/view/inputmethod/EditorBoundsInfo.java b/core/java/android/view/inputmethod/EditorBoundsInfo.java
index df82438b7132..0f6842b7be21 100644
--- a/core/java/android/view/inputmethod/EditorBoundsInfo.java
+++ b/core/java/android/view/inputmethod/EditorBoundsInfo.java
@@ -127,7 +127,7 @@ public final class EditorBoundsInfo implements Parcelable {
};
/**
- * Builder for {@link CursorAnchorInfo}.
+ * Builder for {@link EditorBoundsInfo}.
*/
public static final class Builder {
private RectF mEditorBounds = null;
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 09a14484095e..6b7a6e946d0e 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -960,6 +960,11 @@ public class EditorInfo implements InputType, Parcelable {
* Write debug output of this object.
*/
public void dump(Printer pw, String prefix) {
+ dump(pw, prefix, true /* dumpExtras */);
+ }
+
+ /** @hide */
+ public void dump(Printer pw, String prefix, boolean dumpExtras) {
pw.println(prefix + "inputType=0x" + Integer.toHexString(inputType)
+ " imeOptions=0x" + Integer.toHexString(imeOptions)
+ " privateImeOptions=" + privateImeOptions);
@@ -975,7 +980,9 @@ public class EditorInfo implements InputType, Parcelable {
+ " autofillId=" + autofillId
+ " fieldId=" + fieldId
+ " fieldName=" + fieldName);
- pw.println(prefix + "extras=" + extras);
+ if (dumpExtras) {
+ pw.println(prefix + "extras=" + extras);
+ }
pw.println(prefix + "hintLocales=" + hintLocales);
pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
if (targetInputMethodUser != null) {
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index c78b810f0b1f..70279cc8e845 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -111,6 +111,22 @@ public final class InlineSuggestionsRequest implements Parcelable {
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
/**
+ * Whether the IME supports inline suggestions from the default Autofill service that
+ * provides the input view.
+ *
+ * Note: The default value is {@code true}.
+ */
+ private boolean mServiceSupported;
+
+ /**
+ * Whether the IME supports inline suggestions from the application that provides the
+ * input view.
+ *
+ * Note: The default value is {@code true}.
+ */
+ private boolean mClientSupported;
+
+ /**
* @hide
* @see {@link #mHostInputToken}.
*/
@@ -204,6 +220,14 @@ public final class InlineSuggestionsRequest implements Parcelable {
return Bundle.EMPTY;
}
+ private static boolean defaultServiceSupported() {
+ return true;
+ }
+
+ private static boolean defaultClientSupported() {
+ return true;
+ }
+
/** @hide */
abstract static class BaseBuilder {
abstract Builder setInlinePresentationSpecs(
@@ -216,15 +240,25 @@ public final class InlineSuggestionsRequest implements Parcelable {
abstract Builder setHostDisplayId(int value);
}
+ /** @hide */
+ public boolean isServiceSupported() {
+ return mServiceSupported;
+ }
+
+ /** @hide */
+ public boolean isClientSupported() {
+ return mClientSupported;
+ }
+
- // Code below generated by codegen v1.0.23.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -240,7 +274,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
@NonNull Bundle extras,
@Nullable IBinder hostInputToken,
int hostDisplayId,
- @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
+ @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
+ boolean serviceSupported,
+ boolean clientSupported) {
this.mMaxSuggestionCount = maxSuggestionCount;
this.mInlinePresentationSpecs = inlinePresentationSpecs;
com.android.internal.util.AnnotationValidations.validate(
@@ -257,6 +293,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+ this.mServiceSupported = serviceSupported;
+ this.mClientSupported = clientSupported;
onConstructed();
}
@@ -340,7 +378,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
/**
- * Specifies the UI specification for the inline suggestion tooltip in the response.
+ * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+ *
+ * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
*/
@DataClass.Generated.Member
public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -361,7 +401,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
"extras = " + mExtras + ", " +
"hostInputToken = " + mHostInputToken + ", " +
"hostDisplayId = " + mHostDisplayId + ", " +
- "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
+ "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
+ "serviceSupported = " + mServiceSupported + ", " +
+ "clientSupported = " + mClientSupported +
" }";
}
@@ -385,7 +427,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
&& extrasEquals(that.mExtras)
&& java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
&& mHostDisplayId == that.mHostDisplayId
- && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
+ && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
+ && mServiceSupported == that.mServiceSupported
+ && mClientSupported == that.mClientSupported;
}
@Override
@@ -403,6 +447,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
_hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
_hash = 31 * _hash + mHostDisplayId;
_hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
+ _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
+ _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
return _hash;
}
@@ -413,6 +459,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
// void parcelFieldName(Parcel dest, int flags) { ... }
int flg = 0;
+ if (mServiceSupported) flg |= 0x100;
+ if (mClientSupported) flg |= 0x200;
if (mHostInputToken != null) flg |= 0x20;
if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
dest.writeInt(flg);
@@ -438,6 +486,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
// static FieldType unparcelFieldName(Parcel in) { ... }
int flg = in.readInt();
+ boolean serviceSupported = (flg & 0x100) != 0;
+ boolean clientSupported = (flg & 0x200) != 0;
int maxSuggestionCount = in.readInt();
List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
@@ -464,6 +514,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+ this.mServiceSupported = serviceSupported;
+ this.mClientSupported = clientSupported;
onConstructed();
}
@@ -497,6 +549,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
private @Nullable IBinder mHostInputToken;
private int mHostDisplayId;
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
+ private boolean mServiceSupported;
+ private boolean mClientSupported;
private long mBuilderFieldsSet = 0L;
@@ -629,7 +683,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
/**
- * Specifies the UI specification for the inline suggestion tooltip in the response.
+ * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+ *
+ * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
*/
@DataClass.Generated.Member
public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -639,10 +695,38 @@ public final class InlineSuggestionsRequest implements Parcelable {
return this;
}
+ /**
+ * Whether the IME supports inline suggestions from the default Autofill service that
+ * provides the input view.
+ *
+ * Note: The default value is {@code true}.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setServiceSupported(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x100;
+ mServiceSupported = value;
+ return this;
+ }
+
+ /**
+ * Whether the IME supports inline suggestions from the application that provides the
+ * input view.
+ *
+ * Note: The default value is {@code true}.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setClientSupported(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x200;
+ mClientSupported = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull InlineSuggestionsRequest build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x100; // Mark builder used
+ mBuilderFieldsSet |= 0x400; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -665,6 +749,12 @@ public final class InlineSuggestionsRequest implements Parcelable {
if ((mBuilderFieldsSet & 0x80) == 0) {
mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
}
+ if ((mBuilderFieldsSet & 0x100) == 0) {
+ mServiceSupported = defaultServiceSupported();
+ }
+ if ((mBuilderFieldsSet & 0x200) == 0) {
+ mClientSupported = defaultClientSupported();
+ }
InlineSuggestionsRequest o = new InlineSuggestionsRequest(
mMaxSuggestionCount,
mInlinePresentationSpecs,
@@ -673,12 +763,14 @@ public final class InlineSuggestionsRequest implements Parcelable {
mExtras,
mHostInputToken,
mHostDisplayId,
- mInlineTooltipPresentationSpec);
+ mInlineTooltipPresentationSpec,
+ mServiceSupported,
+ mClientSupported);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x100) != 0) {
+ if ((mBuilderFieldsSet & 0x400) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -686,10 +778,10 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
@DataClass.Generated(
- time = 1621415989607L,
- codegenVersion = "1.0.23",
+ time = 1615798784918L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate boolean mServiceSupported\nprivate boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static boolean defaultServiceSupported()\nprivate static boolean defaultClientSupported()\npublic boolean isServiceSupported()\npublic boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a0a3b4f9c520..1fbf275418fe 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1423,6 +1423,20 @@ public final class InputMethodManager {
}
/**
+ * Returns {@code true} if currently selected IME supports Stylus handwriting.
+ * If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be
+ * called and Stylus touch should continue as normal touch input.
+ * @see #startStylusHandwriting(View)
+ */
+ public boolean isStylusHandwritingAvailable() {
+ try {
+ return mService.isStylusHandwritingAvailable();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the list of installed input methods for the specified user.
*
* @param userId user ID to query
@@ -2014,10 +2028,13 @@ public final class InputMethodManager {
* pointers will be {@code android.view.MotionEvent#FLAG_CANCELED} cancelled.
*
* If Stylus handwriting mode is not supported or cannot be fulfilled for any reason by IME,
- * request will be ignored and Stylus touch will continue as normal touch input.
+ * request will be ignored and Stylus touch will continue as normal touch input. Ideally,
+ * {@link #isStylusHandwritingAvailable()} should be called first to determine if stylus
+ * handwriting is supported by IME.
*
* @param view the View for which stylus handwriting is requested. It and
* {@link View#hasWindowFocus its window} must be {@link View#hasFocus focused}.
+ * @see #isStylusHandwritingAvailable()
*/
public void startStylusHandwriting(@NonNull View view) {
// Re-dispatch if there is a context mismatch.
@@ -2596,7 +2613,7 @@ public final class InputMethodManager {
try {
mService.hideSoftInput(mClient, windowToken, 0 /* flags */,
null /* resultReceiver */,
- SoftInputShowHideReason.HIDE_SOFT_INPUT);
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2989,7 +3006,8 @@ public final class InputMethodManager {
*/
@Deprecated
public void hideSoftInputFromInputMethod(IBinder token, int flags) {
- InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags);
+ InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
+ flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
}
/**
@@ -3590,7 +3608,7 @@ public final class InputMethodManager {
p.println(" mServedConnecting=" + mServedConnecting);
if (mCurrentTextBoxAttribute != null) {
p.println(" mCurrentTextBoxAttribute:");
- mCurrentTextBoxAttribute.dump(p, " ");
+ mCurrentTextBoxAttribute.dump(p, " ", false /* dumpExtras */);
} else {
p.println(" mCurrentTextBoxAttribute: null");
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 231ae084dd6c..184e7bca963b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4363,8 +4363,35 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int delta = Math.round(axisValue * mVerticalScrollFactor);
if (delta != 0) {
+ // If we're moving down, we want the top item. If we're moving up, bottom item.
+ final int motionIndex = delta > 0 ? 0 : getChildCount() - 1;
+
+ int motionViewPrevTop = 0;
+ View motionView = this.getChildAt(motionIndex);
+ if (motionView != null) {
+ motionViewPrevTop = motionView.getTop();
+ }
+
+ final int overscrollMode = getOverScrollMode();
+
if (!trackMotionScroll(delta, delta)) {
return true;
+ } else if (!event.isFromSource(InputDevice.SOURCE_MOUSE) && motionView != null
+ && (overscrollMode == OVER_SCROLL_ALWAYS
+ || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS
+ && !contentFits()))) {
+ int motionViewRealTop = motionView.getTop();
+ float overscroll = (delta - (motionViewRealTop - motionViewPrevTop))
+ / ((float) getHeight());
+ if (delta > 0) {
+ mEdgeGlowTop.onPullDistance(overscroll, 0.5f);
+ mEdgeGlowTop.onRelease();
+ } else {
+ mEdgeGlowBottom.onPullDistance(-overscroll, 0.5f);
+ mEdgeGlowBottom.onRelease();
+ }
+ invalidate();
+ return true;
}
}
break;
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 9c0900b35de6..2c612804d718 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.graphics.Rect;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
@@ -174,12 +173,6 @@ public class EditText extends TextView {
return EditText.class.getName();
}
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- setHandwritingArea(new Rect(0, 0, w, h));
- }
-
/** @hide */
@Override
protected boolean supportsAutoSizeText() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 285a40779b90..8127db537c08 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4633,12 +4633,18 @@ public class Editor {
builder.setMatrix(mViewToScreenMatrix);
if (includeEditorBounds) {
- final RectF bounds = new RectF();
- bounds.set(0 /* left */, 0 /* top */, mTextView.getWidth(), mTextView.getHeight());
+ final RectF editorBounds = new RectF();
+ editorBounds.set(0 /* left */, 0 /* top */,
+ mTextView.getWidth(), mTextView.getHeight());
+ final RectF handwritingBounds = new RectF(
+ -mTextView.getHandwritingBoundsOffsetLeft(),
+ -mTextView.getHandwritingBoundsOffsetTop(),
+ mTextView.getWidth() + mTextView.getHandwritingBoundsOffsetRight(),
+ mTextView.getHeight() + mTextView.getHandwritingBoundsOffsetBottom());
EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
- //TODO(b/210039666): add Handwriting bounds once they're available.
- builder.setEditorBoundsInfo(
- boundsBuilder.setEditorBounds(bounds).build());
+ EditorBoundsInfo editorBoundsInfo = boundsBuilder.setEditorBounds(editorBounds)
+ .setHandwritingBounds(handwritingBounds).build();
+ builder.setEditorBoundsInfo(editorBoundsInfo);
}
if (includeCharacterBounds || includeInsertionMarker) {
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 018cba7f95e5..2dbfd7e5b2e2 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -872,15 +872,39 @@ public class HorizontalScrollView extends FrameLayout {
final int range = getScrollRange();
int oldScrollX = mScrollX;
int newScrollX = oldScrollX + delta;
+
+ final int overscrollMode = getOverScrollMode();
+ boolean canOverscroll = !event.isFromSource(InputDevice.SOURCE_MOUSE)
+ && (overscrollMode == OVER_SCROLL_ALWAYS
+ || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0));
+ boolean absorbed = false;
+
if (newScrollX < 0) {
+ if (canOverscroll) {
+ mEdgeGlowLeft.onPullDistance(-(float) newScrollX / getWidth(),
+ 0.5f);
+ mEdgeGlowLeft.onRelease();
+ invalidate();
+ absorbed = true;
+ }
newScrollX = 0;
} else if (newScrollX > range) {
+ if (canOverscroll) {
+ mEdgeGlowRight.onPullDistance(
+ (float) (newScrollX - range) / getWidth(), 0.5f);
+ mEdgeGlowRight.onRelease();
+ invalidate();
+ absorbed = true;
+ }
newScrollX = range;
}
if (newScrollX != oldScrollX) {
super.scrollTo(newScrollX, mScrollY);
return true;
}
+ if (absorbed) {
+ return true;
+ }
}
}
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 8e293f4b356d..61a7599e8f73 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -52,9 +52,9 @@ import android.widget.RemoteViews.InteractionHandler;
import com.android.internal.widget.IRemoteViewsFactory;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.concurrent.Executor;
/**
@@ -424,17 +424,17 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
* adapter that have not yet had their RemoteViews loaded.
*/
private class RemoteViewsFrameLayoutRefSet
- extends SparseArray<LinkedList<RemoteViewsFrameLayout>> {
+ extends SparseArray<ArrayList<RemoteViewsFrameLayout>> {
/**
* Adds a new reference to a RemoteViewsFrameLayout returned by the adapter.
*/
public void add(int position, RemoteViewsFrameLayout layout) {
- LinkedList<RemoteViewsFrameLayout> refs = get(position);
+ ArrayList<RemoteViewsFrameLayout> refs = get(position);
// Create the list if necessary
if (refs == null) {
- refs = new LinkedList<>();
+ refs = new ArrayList<>();
put(position, refs);
}
@@ -451,7 +451,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
if (view == null) return;
// Remove this set from the original mapping
- final LinkedList<RemoteViewsFrameLayout> refs = removeReturnOld(position);
+ final ArrayList<RemoteViewsFrameLayout> refs = removeReturnOld(position);
if (refs != null) {
// Notify all the references for that position of the newly loaded RemoteViews
for (final RemoteViewsFrameLayout ref : refs) {
@@ -467,7 +467,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
if (rvfl.cacheIndex < 0) {
return;
}
- final LinkedList<RemoteViewsFrameLayout> refs = get(rvfl.cacheIndex);
+ final ArrayList<RemoteViewsFrameLayout> refs = get(rvfl.cacheIndex);
if (refs != null) {
refs.remove(rvfl);
}
@@ -933,12 +933,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
Runnable r = () -> {
synchronized (sCachedRemoteViewsCaches) {
- if (sCachedRemoteViewsCaches.containsKey(key)) {
- sCachedRemoteViewsCaches.remove(key);
- }
- if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) {
- sRemoteViewsCacheRemoveRunnables.remove(key);
- }
+ sCachedRemoteViewsCaches.remove(key);
+ sRemoteViewsCacheRemoveRunnables.remove(key);
}
};
sRemoteViewsCacheRemoveRunnables.put(key, r);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 15cd17b20f4f..2acd50c9e169 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -939,15 +939,38 @@ public class ScrollView extends FrameLayout {
final int range = getScrollRange();
int oldScrollY = mScrollY;
int newScrollY = oldScrollY - delta;
+
+ final int overscrollMode = getOverScrollMode();
+ boolean canOverscroll = !event.isFromSource(InputDevice.SOURCE_MOUSE)
+ && (overscrollMode == OVER_SCROLL_ALWAYS
+ || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0));
+ boolean absorbed = false;
+
if (newScrollY < 0) {
+ if (canOverscroll) {
+ mEdgeGlowTop.onPullDistance(-(float) newScrollY / getHeight(), 0.5f);
+ mEdgeGlowTop.onRelease();
+ invalidate();
+ absorbed = true;
+ }
newScrollY = 0;
} else if (newScrollY > range) {
+ if (canOverscroll) {
+ mEdgeGlowBottom.onPullDistance(
+ (float) (newScrollY - range) / getHeight(), 0.5f);
+ mEdgeGlowBottom.onRelease();
+ invalidate();
+ absorbed = true;
+ }
newScrollY = range;
}
if (newScrollY != oldScrollY) {
super.scrollTo(mScrollX, newScrollY);
return true;
}
+ if (absorbed) {
+ return true;
+ }
}
break;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e745b8cf769b..8090aad22994 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -144,6 +144,7 @@ import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseIntArray;
@@ -791,6 +792,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
private int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
+ // The auto option for LINE_BREAK_WORD_STYLE_PHRASE may not be applied in recycled view due to
+ // one-way flag flipping. This is a tentative limitation during experiment and will not have the
+ // issue once this is finalized to LINE_BREAK_WORD_STYLE_PHRASE_AUTO option.
+ private boolean mUserSpeficiedLineBreakwordStyle = false;
+
// This is used to reflect the current user preference for changing font weight and making text
// more bold.
private int mFontWeightAdjustment;
@@ -1462,6 +1468,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
+ if (a.hasValue(attr)) {
+ mUserSpeficiedLineBreakwordStyle = true;
+ }
mLineBreakWordStyle = a.getInt(attr,
LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
break;
@@ -4209,6 +4218,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextAppearance_lineBreakWordStyle:
attributes.mHasLineBreakWordStyle = true;
+ mUserSpeficiedLineBreakwordStyle = true;
attributes.mLineBreakWordStyle =
appearance.getInt(attr, attributes.mLineBreakWordStyle);
break;
@@ -4910,6 +4920,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @param lineBreakWordStyle the line break word style for the tet
*/
public void setLineBreakWordStyle(@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
+ mUserSpeficiedLineBreakwordStyle = true;
if (mLineBreakWordStyle != lineBreakWordStyle) {
mLineBreakWordStyle = lineBreakWordStyle;
if (mLayout != null) {
@@ -4945,8 +4956,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see PrecomputedText
*/
public @NonNull PrecomputedText.Params getTextMetricsParams() {
+ final boolean autoPhraseBreaking =
+ !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
return new PrecomputedText.Params(new TextPaint(mTextPaint),
- LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle),
+ LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle,
+ autoPhraseBreaking),
getTextDirectionHeuristic(),
mBreakStrategy, mHyphenationFrequency);
}
@@ -4966,6 +4981,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
LineBreakConfig lineBreakConfig = params.getLineBreakConfig();
mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
+ mUserSpeficiedLineBreakwordStyle = true;
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -6502,10 +6518,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mTextDir == null) {
mTextDir = getTextDirectionHeuristic();
}
+ final boolean autoPhraseBreaking =
+ !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
- mLineBreakStyle, mLineBreakWordStyle));
+ mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
throw new IllegalArgumentException(
@@ -9403,6 +9422,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// TODO: code duplication with makeSingleLayout()
if (mHintLayout == null) {
+ final boolean autoPhraseBreaking =
+ !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
mHint.length(), mTextPaint, hintWidth)
.setAlignment(alignment)
@@ -9415,7 +9437,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
.setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
- mLineBreakStyle, mLineBreakWordStyle));
+ mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
if (shouldEllipsize) {
builder.setEllipsize(mEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9519,6 +9541,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
if (result == null) {
+ final boolean autoPhraseBreaking =
+ !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
0, mTransformed.length(), mTextPaint, wantWidth)
.setAlignment(alignment)
@@ -9531,7 +9556,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
.setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
- mLineBreakStyle, mLineBreakWordStyle));
+ mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9889,7 +9914,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain(
text, 0, text.length(), mTempTextPaint, Math.round(availableSpace.right));
-
+ final boolean autoPhraseBreaking =
+ !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
layoutBuilder.setAlignment(getLayoutAlignment())
.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
.setIncludePad(getIncludeFontPadding())
@@ -9900,7 +9927,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
.setTextDirection(getTextDirectionHeuristic())
.setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
- mLineBreakStyle, mLineBreakWordStyle));
+ mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
final StaticLayout layout = layoutBuilder.build();
@@ -12466,6 +12493,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
float viewportToContentVerticalOffset) {
final int minLine = mLayout.getLineForOffset(startIndex);
final int maxLine = mLayout.getLineForOffset(endIndex - 1);
+ final Rect rect = new Rect();
+ getLocalVisibleRect(rect);
+ final RectF visibleRect = new RectF(rect);
for (int line = minLine; line <= maxLine; ++line) {
final int lineStart = mLayout.getLineStart(line);
final int lineEnd = mLayout.getLineEnd(line);
@@ -12480,37 +12510,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
for (int offset = offsetStart; offset < offsetEnd; ++offset) {
final float charWidth = widths[offset - offsetStart];
final boolean isRtl = mLayout.isRtlCharAt(offset);
- final float primary = mLayout.getPrimaryHorizontal(offset);
- final float secondary = mLayout.getSecondaryHorizontal(offset);
// TODO: This doesn't work perfectly for text with custom styles and
// TAB chars.
final float left;
- final float right;
if (ltrLine) {
if (isRtl) {
- left = secondary - charWidth;
- right = secondary;
+ left = mLayout.getSecondaryHorizontal(offset) - charWidth;
} else {
- left = primary;
- right = primary + charWidth;
+ left = mLayout.getPrimaryHorizontal(offset);
}
} else {
if (!isRtl) {
- left = secondary;
- right = secondary + charWidth;
+ left = mLayout.getSecondaryHorizontal(offset);
} else {
- left = primary - charWidth;
- right = primary;
+ left = mLayout.getPrimaryHorizontal(offset) - charWidth;
}
}
+ final float right = left + charWidth;
// TODO: Check top-right and bottom-left as well.
final float localLeft = left + viewportToContentHorizontalOffset;
final float localRight = right + viewportToContentHorizontalOffset;
final float localTop = top + viewportToContentVerticalOffset;
final float localBottom = bottom + viewportToContentVerticalOffset;
- final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
+ final boolean isTopLeftVisible = visibleRect.contains(localLeft, localTop);
final boolean isBottomRightVisible =
- isPositionVisible(localRight, localBottom);
+ visibleRect.contains(localRight, localBottom);
int characterBoundsFlags = 0;
if (isTopLeftVisible || isBottomRightVisible) {
characterBoundsFlags |= FLAG_HAS_VISIBLE_REGION;
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index f72164e1f53f..56e910769cb5 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -23,8 +23,10 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,7 +68,7 @@ public final class TaskFragmentInfo implements Parcelable {
private final List<IBinder> mActivities = new ArrayList<>();
/** Relative position of the fragment's top left corner in the parent container. */
- private final Point mPositionInParent;
+ private final Point mPositionInParent = new Point();
/**
* Whether the last running activity in the TaskFragment was finished due to clearing task while
@@ -80,21 +82,31 @@ public final class TaskFragmentInfo implements Parcelable {
*/
private final boolean mIsTaskFragmentClearedForPip;
+ /**
+ * The maximum {@link ActivityInfo.WindowLayout#minWidth} and
+ * {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
+ * activities.
+ */
+ @NonNull
+ private final Point mMinimumDimensions = new Point();
+
/** @hide */
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
@NonNull Configuration configuration, int runningActivityCount,
boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
- boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip) {
+ boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
+ @NonNull Point minimumDimensions) {
mFragmentToken = requireNonNull(fragmentToken);
mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mRunningActivityCount = runningActivityCount;
mIsVisible = isVisible;
mActivities.addAll(activities);
- mPositionInParent = requireNonNull(positionInParent);
+ mPositionInParent.set(positionInParent);
mIsTaskClearedForReuse = isTaskClearedForReuse;
mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
+ mMinimumDimensions.set(minimumDimensions);
}
@NonNull
@@ -154,6 +166,26 @@ public final class TaskFragmentInfo implements Parcelable {
}
/**
+ * Returns the minimum width this TaskFragment can be resized to.
+ * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * that {@link Rect#width()} is shorter than the reported value.
+ * @hide pending unhide
+ */
+ public int getMinimumWidth() {
+ return mMinimumDimensions.x;
+ }
+
+ /**
+ * Returns the minimum width this TaskFragment can be resized to.
+ * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * that {@link Rect#height()} is shorter than the reported value.
+ * @hide pending unhide
+ */
+ public int getMinimumHeight() {
+ return mMinimumDimensions.y;
+ }
+
+ /**
* Returns {@code true} if the parameters that are important for task fragment organizers are
* equal between this {@link TaskFragmentInfo} and {@param that}.
*/
@@ -170,7 +202,8 @@ public final class TaskFragmentInfo implements Parcelable {
&& mActivities.equals(that.mActivities)
&& mPositionInParent.equals(that.mPositionInParent)
&& mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
- && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip;
+ && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
+ && mMinimumDimensions.equals(that.mMinimumDimensions);
}
private TaskFragmentInfo(Parcel in) {
@@ -180,9 +213,10 @@ public final class TaskFragmentInfo implements Parcelable {
mRunningActivityCount = in.readInt();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
- mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
+ mPositionInParent.readFromParcel(in);
mIsTaskClearedForReuse = in.readBoolean();
mIsTaskFragmentClearedForPip = in.readBoolean();
+ mMinimumDimensions.readFromParcel(in);
}
/** @hide */
@@ -194,9 +228,10 @@ public final class TaskFragmentInfo implements Parcelable {
dest.writeInt(mRunningActivityCount);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
- dest.writeTypedObject(mPositionInParent, flags);
+ mPositionInParent.writeToParcel(dest, flags);
dest.writeBoolean(mIsTaskClearedForReuse);
dest.writeBoolean(mIsTaskFragmentClearedForPip);
+ mMinimumDimensions.writeToParcel(dest, flags);
}
@NonNull
@@ -224,6 +259,7 @@ public final class TaskFragmentInfo implements Parcelable {
+ " positionInParent=" + mPositionInParent
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
+ " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip
+ + " minimumDimensions" + mMinimumDimensions
+ "}";
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 51da61ffb9c9..c81184fb2383 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -107,8 +107,11 @@ public final class TransitionInfo implements Parcelable {
*/
public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
+ /** The container is an input-method window. */
+ public static final int FLAG_IS_INPUT_METHOD = 1 << 8;
+
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
- public static final int FLAG_FIRST_CUSTOM = 1 << 8;
+ public static final int FLAG_FIRST_CUSTOM = 1 << 9;
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
@@ -121,6 +124,7 @@ public final class TransitionInfo implements Parcelable {
FLAG_IS_DISPLAY,
FLAG_OCCLUDES_KEYGUARD,
FLAG_DISPLAY_HAS_ALERT_WINDOWS,
+ FLAG_IS_INPUT_METHOD,
FLAG_FIRST_CUSTOM
})
public @interface ChangeFlags {}
@@ -300,6 +304,9 @@ public final class TransitionInfo implements Parcelable {
if ((flags & FLAG_IS_WALLPAPER) != 0) {
sb.append("IS_WALLPAPER");
}
+ if ((flags & FLAG_IS_INPUT_METHOD) != 0) {
+ sb.append("IS_INPUT_METHOD");
+ }
if ((flags & FLAG_TRANSLUCENT) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
}
diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
index 48211a8234ee..14046945ede0 100644
--- a/core/java/android/window/TransitionRequestInfo.java
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -16,6 +16,8 @@
package android.window;
+import static android.view.WindowManager.transitTypeToString;
+
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
@@ -366,7 +368,7 @@ public final class TransitionRequestInfo implements Parcelable {
// String fieldNameToString() { ... }
return "TransitionRequestInfo { " +
- "type = " + mType + ", " +
+ "type = " + transitTypeToString(mType) + ", " +
"triggerTask = " + mTriggerTask + ", " +
"remoteTransition = " + mRemoteTransition + ", " +
"displayChange = " + mDisplayChange +
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 7dc039d44f95..633d87937049 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -384,12 +384,10 @@ public final class WindowContainerTransaction implements Parcelable {
*/
@NonNull
public WindowContainerTransaction setAdjacentRoots(
- @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2,
- boolean moveTogether) {
+ @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
root1.asBinder(),
- root2.asBinder(),
- moveTogether));
+ root2.asBinder()));
return this;
}
@@ -1106,9 +1104,6 @@ public final class WindowContainerTransaction implements Parcelable {
private boolean mReparentTopOnly;
- // TODO(b/207185041): Remove this once having a single-top root for split screen.
- private boolean mMoveAdjacentTogether;
-
@Nullable
private int[] mWindowingModes;
@@ -1171,12 +1166,10 @@ public final class WindowContainerTransaction implements Parcelable {
}
/** Create a hierarchy op for setting adjacent root tasks. */
- public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2,
- boolean moveTogether) {
+ public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) {
return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
.setContainer(root1)
.setReparentContainer(root2)
- .setMoveAdjacentTogether(moveTogether)
.build();
}
@@ -1223,7 +1216,6 @@ public final class WindowContainerTransaction implements Parcelable {
mInsetsProviderFrame = copy.mInsetsProviderFrame;
mToTop = copy.mToTop;
mReparentTopOnly = copy.mReparentTopOnly;
- mMoveAdjacentTogether = copy.mMoveAdjacentTogether;
mWindowingModes = copy.mWindowingModes;
mActivityTypes = copy.mActivityTypes;
mLaunchOptions = copy.mLaunchOptions;
@@ -1245,7 +1237,6 @@ public final class WindowContainerTransaction implements Parcelable {
}
mToTop = in.readBoolean();
mReparentTopOnly = in.readBoolean();
- mMoveAdjacentTogether = in.readBoolean();
mWindowingModes = in.createIntArray();
mActivityTypes = in.createIntArray();
mLaunchOptions = in.readBundle();
@@ -1300,10 +1291,6 @@ public final class WindowContainerTransaction implements Parcelable {
return mReparentTopOnly;
}
- public boolean getMoveAdjacentTogether() {
- return mMoveAdjacentTogether;
- }
-
public int[] getWindowingModes() {
return mWindowingModes;
}
@@ -1356,8 +1343,7 @@ public final class WindowContainerTransaction implements Parcelable {
return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
return "{SetAdjacentRoot: container=" + mContainer
- + " adjacentRoot=" + mReparent + " mMoveAdjacentTogether="
- + mMoveAdjacentTogether + "}";
+ + " adjacentRoot=" + mReparent + "}";
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
return "{LaunchTask: " + mLaunchOptions + "}";
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
@@ -1413,7 +1399,6 @@ public final class WindowContainerTransaction implements Parcelable {
}
dest.writeBoolean(mToTop);
dest.writeBoolean(mReparentTopOnly);
- dest.writeBoolean(mMoveAdjacentTogether);
dest.writeIntArray(mWindowingModes);
dest.writeIntArray(mActivityTypes);
dest.writeBundle(mLaunchOptions);
@@ -1458,8 +1443,6 @@ public final class WindowContainerTransaction implements Parcelable {
private boolean mReparentTopOnly;
- private boolean mMoveAdjacentTogether;
-
@Nullable
private int[] mWindowingModes;
@@ -1515,11 +1498,6 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
- Builder setMoveAdjacentTogether(boolean moveAdjacentTogether) {
- mMoveAdjacentTogether = moveAdjacentTogether;
- return this;
- }
-
Builder setWindowingModes(@Nullable int[] windowingModes) {
mWindowingModes = windowingModes;
return this;
@@ -1570,7 +1548,6 @@ public final class WindowContainerTransaction implements Parcelable {
hierarchyOp.mInsetsProviderFrame = mInsetsProviderFrame;
hierarchyOp.mToTop = mToTop;
hierarchyOp.mReparentTopOnly = mReparentTopOnly;
- hierarchyOp.mMoveAdjacentTogether = mMoveAdjacentTogether;
hierarchyOp.mLaunchOptions = mLaunchOptions;
hierarchyOp.mActivityIntent = mActivityIntent;
hierarchyOp.mPendingIntent = mPendingIntent;
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 874e3f4ae26a..50afb3ee0a03 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -28,6 +28,7 @@ import static com.android.internal.accessibility.util.AccessibilityUtils.isUserS
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -102,16 +103,7 @@ public class AccessibilityShortcutChooserActivity extends Activity {
final AccessibilityTarget target = mTargets.get(position);
if ((target instanceof AccessibilityServiceTarget) && !target.isShortcutEnabled()) {
- mPermissionDialog = new AlertDialog.Builder(this)
- .setView(createEnableDialogContentView(this,
- (AccessibilityServiceTarget) target,
- v -> {
- mPermissionDialog.dismiss();
- mTargetAdapter.notifyDataSetChanged();
- },
- v -> mPermissionDialog.dismiss()))
- .create();
- mPermissionDialog.show();
+ showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target, mTargetAdapter);
return;
}
@@ -119,6 +111,24 @@ public class AccessibilityShortcutChooserActivity extends Activity {
mTargetAdapter.notifyDataSetChanged();
}
+ private void showPermissionDialogIfNeeded(Context context,
+ AccessibilityServiceTarget serviceTarget, ShortcutTargetAdapter targetAdapter) {
+ if (mPermissionDialog != null) {
+ return;
+ }
+
+ mPermissionDialog = new AlertDialog.Builder(context)
+ .setView(createEnableDialogContentView(context, serviceTarget,
+ v -> {
+ mPermissionDialog.dismiss();
+ targetAdapter.notifyDataSetChanged();
+ },
+ v -> mPermissionDialog.dismiss()))
+ .setOnDismissListener(dialog -> mPermissionDialog = null)
+ .create();
+ mPermissionDialog.show();
+ }
+
private void onDoneButtonClicked() {
mTargets.clear();
mTargets.addAll(getTargets(this, mShortcutType));
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index a611d65d6260..6bc7ac6cd7d9 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -168,6 +168,29 @@ public final class AccessibilityStatsLogUtils {
}
/**
+ * Logs the duration for the window magnifier's following typing focus session.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ public static void logMagnificationFollowTypingFocusSession(long duration) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.MAGNIFICATION_FOLLOW_TYPING_FOCUS_ACTIVATED_SESSION_REPORTED,
+ duration);
+ }
+
+ /**
+ * Logs the duration for the magnification session which is activated by the triple tap and
+ * hold gesture.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ public static void logMagnificationTripleTapAndHoldSession(long duration) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.MAGNIFICATION_TRIPLE_TAP_AND_HOLD_ACTIVATED_SESSION_REPORTED,
+ duration);
+ }
+
+ /**
* Logs the warning status of the non-a11yTool service. Calls this when the warning status is
* changed.
*
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index b19ac2fec640..115a9d772658 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -18,7 +18,6 @@ package com.android.internal.app;
import static android.app.prediction.AppTargetEvent.ACTION_LAUNCH;
-import android.annotation.Nullable;
import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
@@ -34,6 +33,7 @@ import android.util.Log;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -51,16 +51,17 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
private final AppPredictor mAppPredictor;
private final Context mContext;
- private final Map<ComponentName, Integer> mTargetRanks = new HashMap<>();
- private final Map<ComponentName, Integer> mTargetScores = new HashMap<>();
private final UserHandle mUser;
private final Intent mIntent;
private final String mReferrerPackage;
+
+ private final ModelBuilder mModelBuilder;
+ private ResolverComparatorModel mComparatorModel;
+
// If this is non-null (and this is not destroyed), it means APS is disabled and we should fall
// back to using the ResolverRankerService.
// TODO: responsibility for this fallback behavior can live outside of the AppPrediction client.
private ResolverRankerServiceResolverComparator mResolverRankerService;
- private AppPredictionServiceComparatorModel mComparatorModel;
AppPredictionServiceResolverComparator(
Context context,
@@ -76,7 +77,20 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
mUser = user;
mReferrerPackage = referrerPackage;
setChooserActivityLogger(chooserActivityLogger);
- mComparatorModel = buildUpdatedModel();
+
+ mModelBuilder = new ModelBuilder(appPredictor, user);
+ mComparatorModel = mModelBuilder.buildFromRankedList(Collections.emptyList());
+ }
+
+ @Override
+ void destroy() {
+ if (mResolverRankerService != null) {
+ mResolverRankerService.destroy();
+ mResolverRankerService = null;
+
+ // TODO: may not be necessary to build a new model, since we're destroying anyways.
+ mComparatorModel = mModelBuilder.buildFallbackModel(mResolverRankerService);
+ }
}
@Override
@@ -85,6 +99,29 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
}
@Override
+ float getScore(ComponentName name) {
+ return mComparatorModel.getScore(name);
+ }
+
+ @Override
+ void updateModel(ComponentName componentName) {
+ mComparatorModel.notifyOnTargetSelected(componentName);
+ }
+
+ @Override
+ void handleResultMessage(Message msg) {
+ // Null value is okay if we have defaulted to the ResolverRankerService.
+ if (msg.what == RANKER_SERVICE_RESULT && msg.obj != null) {
+ // TODO: this probably never happens? The sorting callback circumvents the Handler
+ // design to call handleResult() directly instead of sending the list through a Message.
+ // (OK to leave as-is since the Handler design is going away soon.)
+ mComparatorModel = mModelBuilder.buildFromRankedList((List<AppTarget>) msg.obj);
+ } else if (msg.obj == null && mResolverRankerService == null) {
+ Log.e(TAG, "Unexpected null result");
+ }
+ }
+
+ @Override
void doCompute(List<ResolvedComponentInfo> targets) {
if (targets.isEmpty()) {
mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT);
@@ -104,121 +141,113 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
sortedAppTargets -> {
if (sortedAppTargets.isEmpty()) {
Log.i(TAG, "AppPredictionService disabled. Using resolver.");
- // APS for chooser is disabled. Fallback to resolver.
- mResolverRankerService =
- new ResolverRankerServiceResolverComparator(
- mContext, mIntent, mReferrerPackage,
- () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT),
- getChooserActivityLogger());
- mComparatorModel = buildUpdatedModel();
- mResolverRankerService.compute(targets);
+ setupFallbackModel(targets);
} else {
Log.i(TAG, "AppPredictionService response received");
// Skip sending to Handler which takes extra time to dispatch messages.
+ // TODO: the Handler guards some concurrency conditions, so this could
+ // probably result in a race (we're not currently on the Handler thread?).
+ // We'll leave this as-is since we intend to remove the Handler design
+ // shortly, but this is still an unsound shortcut.
handleResult(sortedAppTargets);
}
}
);
}
- @Override
- void handleResultMessage(Message msg) {
- // Null value is okay if we have defaulted to the ResolverRankerService.
- if (msg.what == RANKER_SERVICE_RESULT && msg.obj != null) {
- final List<AppTarget> sortedAppTargets = (List<AppTarget>) msg.obj;
- handleSortedAppTargets(sortedAppTargets);
- } else if (msg.obj == null && mResolverRankerService == null) {
- Log.e(TAG, "Unexpected null result");
- }
+ private void setupFallbackModel(List<ResolvedComponentInfo> targets) {
+ mResolverRankerService =
+ new ResolverRankerServiceResolverComparator(
+ mContext, mIntent, mReferrerPackage,
+ () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT),
+ getChooserActivityLogger());
+ mComparatorModel = mModelBuilder.buildFallbackModel(mResolverRankerService);
+ mResolverRankerService.compute(targets);
}
private void handleResult(List<AppTarget> sortedAppTargets) {
if (mHandler.hasMessages(RANKER_RESULT_TIMEOUT)) {
- handleSortedAppTargets(sortedAppTargets);
+ mComparatorModel = mModelBuilder.buildFromRankedList(sortedAppTargets);
mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
afterCompute();
}
}
- private void handleSortedAppTargets(List<AppTarget> sortedAppTargets) {
- if (checkAppTargetRankValid(sortedAppTargets)) {
- sortedAppTargets.forEach(target -> mTargetScores.put(
- new ComponentName(target.getPackageName(), target.getClassName()),
- target.getRank()));
+ static class ModelBuilder {
+ private final AppPredictor mAppPredictor;
+ private final UserHandle mUser;
+
+ ModelBuilder(AppPredictor appPredictor, UserHandle user) {
+ mAppPredictor = appPredictor;
+ mUser = user;
+ }
+
+ ResolverComparatorModel buildFromRankedList(List<AppTarget> sortedAppTargets) {
+ return new AppPredictionServiceComparatorModel(
+ mAppPredictor, mUser, buildTargetRanksMapFromSortedTargets(sortedAppTargets));
}
- for (int i = 0; i < sortedAppTargets.size(); i++) {
- ComponentName componentName = new ComponentName(
- sortedAppTargets.get(i).getPackageName(),
- sortedAppTargets.get(i).getClassName());
- mTargetRanks.put(componentName, i);
- Log.i(TAG, "handleSortedAppTargets, sortedAppTargets #" + i + ": " + componentName);
+
+ ResolverComparatorModel buildFallbackModel(
+ ResolverRankerServiceResolverComparator fallback) {
+ return adaptLegacyResolverComparatorToComparatorModel(fallback);
}
- mComparatorModel = buildUpdatedModel();
- }
- private boolean checkAppTargetRankValid(List<AppTarget> sortedAppTargets) {
- for (AppTarget target : sortedAppTargets) {
- if (target.getRank() != 0) {
- return true;
+ // The remaining methods would be static if this weren't an inner class (i.e., they don't
+ // depend on any ivars, not even the ones in ModelBuilder).
+
+ private Map<ComponentName, Integer> buildTargetRanksMapFromSortedTargets(
+ List<AppTarget> sortedAppTargets) {
+ Map<ComponentName, Integer> targetRanks = new HashMap<>();
+ for (int i = 0; i < sortedAppTargets.size(); i++) {
+ ComponentName componentName = new ComponentName(
+ sortedAppTargets.get(i).getPackageName(),
+ sortedAppTargets.get(i).getClassName());
+ targetRanks.put(componentName, i);
+ Log.i(TAG, "handleSortedAppTargets, sortedAppTargets #" + i + ": " + componentName);
}
+ return targetRanks;
}
- return false;
- }
- @Override
- float getScore(ComponentName name) {
- return mComparatorModel.getScore(name);
- }
+ // TODO: when the refactoring is further along we'll probably have access to the
+ // comparator's new ResolverComparatorModel API, so we won't have to adapt from the legacy
+ // interface here. On the other hand, AppPredictionServiceResolverComparatorModel (or its
+ // replacement counterpart) shouldn't still be responsible for implementing the
+ // ResolverRankerService fallback logic at that time.
+ private ResolverComparatorModel adaptLegacyResolverComparatorToComparatorModel(
+ AbstractResolverComparator comparator) {
+ return new ResolverComparatorModel() {
+ @Override
+ public Comparator<ResolveInfo> getComparator() {
+ // Adapt the base type, which doesn't declare itself to be an implementation
+ // of {@code Comparator<ResolveInfo>} even though it has the one method.
+ return (lhs, rhs) -> comparator.compare(lhs, rhs);
+ }
- @Override
- void updateModel(ComponentName componentName) {
- mComparatorModel.notifyOnTargetSelected(componentName);
- }
+ @Override
+ public float getScore(ComponentName componentName) {
+ return comparator.getScore(componentName);
+ }
- @Override
- void destroy() {
- if (mResolverRankerService != null) {
- mResolverRankerService.destroy();
- mResolverRankerService = null;
- mComparatorModel = buildUpdatedModel();
+ @Override
+ public void notifyOnTargetSelected(ComponentName componentName) {
+ comparator.updateModel(componentName);
+ }
+ };
}
}
- /**
- * Re-construct an {@code AppPredictionServiceComparatorModel} to replace the current model
- * instance (if any) using the up-to-date {@code AppPredictionServiceResolverComparator} ivar
- * values.
- *
- * TODO: each time we replace the model instance, we're either updating the model to use
- * adjusted data (which is appropriate), or we're providing a (late) value for one of our ivars
- * that wasn't available the last time the model was updated. For those latter cases, we should
- * just avoid creating the model altogether until we have all the prerequisites we'll need. Then
- * we can probably simplify the logic in {@code AppPredictionServiceComparatorModel} since we
- * won't need to handle edge cases when the model data isn't fully prepared.
- * (In some cases, these kinds of "updates" might interleave -- e.g., we might have finished
- * initializing the first time and now want to adjust some data, but still need to wait for
- * changes to propagate to the other ivars before rebuilding the model.)
- */
- private AppPredictionServiceComparatorModel buildUpdatedModel() {
- return new AppPredictionServiceComparatorModel(
- mAppPredictor, mResolverRankerService, mUser, mTargetRanks);
- }
-
// TODO: Finish separating behaviors of AbstractResolverComparator, then (probably) make this a
// standalone class once clients are written in terms of ResolverComparatorModel.
static class AppPredictionServiceComparatorModel implements ResolverComparatorModel {
private final AppPredictor mAppPredictor;
- private final ResolverRankerServiceResolverComparator mResolverRankerService;
private final UserHandle mUser;
private final Map<ComponentName, Integer> mTargetRanks; // Treat as immutable.
AppPredictionServiceComparatorModel(
AppPredictor appPredictor,
- @Nullable ResolverRankerServiceResolverComparator resolverRankerService,
UserHandle user,
Map<ComponentName, Integer> targetRanks) {
mAppPredictor = appPredictor;
- mResolverRankerService = resolverRankerService;
mUser = user;
mTargetRanks = targetRanks;
}
@@ -226,9 +255,6 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
@Override
public Comparator<ResolveInfo> getComparator() {
return (lhs, rhs) -> {
- if (mResolverRankerService != null) {
- return mResolverRankerService.compare(lhs, rhs);
- }
Integer lhsRank = mTargetRanks.get(new ComponentName(lhs.activityInfo.packageName,
lhs.activityInfo.name));
Integer rhsRank = mTargetRanks.get(new ComponentName(rhs.activityInfo.packageName,
@@ -246,9 +272,6 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
@Override
public float getScore(ComponentName name) {
- if (mResolverRankerService != null) {
- return mResolverRankerService.getScore(name);
- }
Integer rank = mTargetRanks.get(name);
if (rank == null) {
Log.w(TAG, "Score requested for unknown component. Did you call compute yet?");
@@ -260,10 +283,6 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
@Override
public void notifyOnTargetSelected(ComponentName componentName) {
- if (mResolverRankerService != null) {
- mResolverRankerService.updateModel(componentName);
- return;
- }
mAppPredictor.notifyAppTargetEvent(
new AppTargetEvent.Builder(
new AppTarget.Builder(
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 66abe30d0123..10bf2767b0c2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1086,6 +1086,19 @@ public class ChooserActivity extends ResolverActivity implements
final Intent resolveIntent = new Intent(originalIntent);
resolveIntent.setComponent(cn);
resolveIntent.setAction(Intent.ACTION_EDIT);
+ String originalAction = originalIntent.getAction();
+ if (Intent.ACTION_SEND.equals(originalAction)) {
+ if (resolveIntent.getData() == null) {
+ Uri uri = resolveIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ if (uri != null) {
+ String mimeType = getContentResolver().getType(uri);
+ resolveIntent.setDataAndType(uri, mimeType);
+ }
+ }
+ } else {
+ Log.e(TAG, originalAction + " is not supported.");
+ return null;
+ }
final ResolveInfo ri = getPackageManager().resolveActivity(
resolveIntent, PackageManager.GET_META_DATA);
if (ri == null || ri.activityInfo == null) {
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 2d68cb472fa3..e74898294c09 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -70,6 +70,7 @@ interface IAppWidgetService {
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
boolean bindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent,
IApplicationThread caller, IBinder token, IServiceConnection connection, int flags);
+ void notifyProviderInheritance(in ComponentName[] componentNames);
@UnsupportedAppUsage
int[] getAppWidgetIds(in ComponentName providerComponent);
diff --git a/core/java/com/android/internal/appwidget/OWNERS b/core/java/com/android/internal/appwidget/OWNERS
new file mode 100644
index 000000000000..0add4f6217dd
--- /dev/null
+++ b/core/java/com/android/internal/appwidget/OWNERS
@@ -0,0 +1,2 @@
+include /core/java/android/appwidget/OWNERS
+
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 8847a490e39c..554155865080 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -47,6 +47,7 @@ interface IPlatformCompat {
* @param appInfo representing the affected app
* @throws SecurityException if logging is not allowed
*/
+ @EnforcePermission("LOG_COMPAT_CHANGE")
void reportChange(long changeId, in ApplicationInfo appInfo);
/**
@@ -60,6 +61,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app in question
* @throws SecurityException if logging is not allowed
*/
+ @EnforcePermission("LOG_COMPAT_CHANGE")
void reportChangeByPackageName(long changeId, in String packageName, int userId);
/**
@@ -72,6 +74,7 @@ interface IPlatformCompat {
* @param uid the UID of the app in question
* @throws SecurityException if logging is not allowed
*/
+ @EnforcePermission("LOG_COMPAT_CHANGE")
void reportChangeByUid(long changeId, int uid);
/**
@@ -90,6 +93,7 @@ interface IPlatformCompat {
* @return {@code true} if the change is enabled for the current app
* @throws SecurityException if logging or reading compat confis is not allowed
*/
+ @EnforcePermission(allOf={"LOG_COMPAT_CHANGE", "READ_COMPAT_CHANGE_CONFIG"})
boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
/**
@@ -115,6 +119,7 @@ interface IPlatformCompat {
* @return {@code true} if the change is enabled for the current app
* @throws SecurityException if logging or reading compat confis is not allowed
*/
+ @EnforcePermission(allOf={"LOG_COMPAT_CHANGE", "READ_COMPAT_CHANGE_CONFIG"})
boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
/**
@@ -140,6 +145,7 @@ interface IPlatformCompat {
* @return {@code true} if the change is enabled for the current app
* @throws SecurityException if logging or reading compat confis is not allowed
*/
+ @EnforcePermission(allOf={"LOG_COMPAT_CHANGE", "READ_COMPAT_CHANGE_CONFIG"})
boolean isChangeEnabledByUid(long changeId, int uid);
/**
@@ -151,6 +157,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app whose changes will be overridden
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
/**
@@ -171,6 +178,7 @@ interface IPlatformCompat {
* on specific apps by their package name
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD")
void putAllOverridesOnReleaseBuilds(in CompatibilityOverridesByPackageConfig overridesByPackage);
/**
@@ -190,6 +198,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app whose changes will be overridden
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD")
void putOverridesOnReleaseBuilds(in CompatibilityOverrideConfig overrides, in String packageName);
/**
@@ -201,6 +210,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app whose changes will be overridden
* @throws SecurityException if overriding changes is not permitted.
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName);
/**
@@ -213,6 +223,7 @@ interface IPlatformCompat {
* @return {@code true} if an override existed
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
boolean clearOverride(long changeId, String packageName);
/**
@@ -225,6 +236,7 @@ interface IPlatformCompat {
* @return {@code true} if an override existed
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
boolean clearOverrideForTest(long changeId, String packageName);
/**
@@ -245,6 +257,7 @@ interface IPlatformCompat {
* removed for specific apps by their package name
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD")
void removeAllOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage);
/**
@@ -266,6 +279,7 @@ interface IPlatformCompat {
* default behaviour
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD")
void removeOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveConfig overridesToRemove, in String packageName);
/**
@@ -280,6 +294,7 @@ interface IPlatformCompat {
* @return The number of changes that were enabled.
* @throws SecurityException if overriding changes is not permitted.
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
@@ -294,6 +309,7 @@ interface IPlatformCompat {
* @return the number of changes that were disabled
* @throws SecurityException if overriding changes is not permitted.
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
@@ -304,6 +320,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app whose overrides will be cleared
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
void clearOverrides(in String packageName);
/**
@@ -314,6 +331,7 @@ interface IPlatformCompat {
* @param packageName the package name of the app whose overrides will be cleared
* @throws SecurityException if overriding changes is not permitted
*/
+ @EnforcePermission("OVERRIDE_COMPAT_CHANGE_CONFIG")
void clearOverridesForTest(in String packageName);
/**
@@ -323,6 +341,7 @@ interface IPlatformCompat {
* @return a {@link CompatibilityChangeConfig}, representing whether a change is enabled for
* the given app or not
*/
+ @EnforcePermission(allOf={"LOG_COMPAT_CHANGE", "READ_COMPAT_CHANGE_CONFIG"})
CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo);
/**
@@ -330,6 +349,7 @@ interface IPlatformCompat {
*
* @return an array of {@link CompatibilityChangeInfo} known to the service
*/
+ @EnforcePermission("READ_COMPAT_CHANGE_CONFIG")
CompatibilityChangeInfo[] listAllChanges();
/**
@@ -338,10 +358,12 @@ interface IPlatformCompat {
*
* @return an array of {@link CompatibilityChangeInfo}
*/
+ @RequiresNoPermission
CompatibilityChangeInfo[] listUIChanges();
/**
* Gets an instance that can determine whether a changeid can be overridden for a package name.
*/
+ @RequiresNoPermission
IOverrideValidator getOverrideValidator();
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 7c08a7bbc826..cbaac5f33eb4 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -572,6 +572,11 @@ public final class SystemUiDeviceConfigFlags {
*/
public static final String CLIPBOARD_OVERLAY_SHOW_ACTIONS = "clipboard_overlay_show_actions";
+ /**
+ * (boolean) Whether to combine the broadcasts APPWIDGET_ENABLED and APPWIDGET_UPDATE
+ */
+ public static final String COMBINED_BROADCAST_ENABLED = "combined_broadcast_enabled";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 563cf0414ab9..58376a77c705 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -62,7 +62,9 @@ import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -232,9 +234,9 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new FileNotFoundException(doc + " is not found under " + parent);
}
- LinkedList<String> path = new LinkedList<>();
+ List<String> path = new ArrayList<>();
while (doc != null && FileUtils.contains(parent, doc)) {
- path.addFirst(getDocIdForFile(doc));
+ path.add(0, getDocIdForFile(doc));
doc = doc.getParentFile();
}
@@ -454,10 +456,10 @@ public abstract class FileSystemProvider extends DocumentsProvider {
File folder, String[] projection, Set<String> exclusion, Bundle queryArgs)
throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveProjection(projection));
- final LinkedList<File> pending = new LinkedList<>();
+ final List<File> pending = new ArrayList<>();
pending.add(folder);
while (!pending.isEmpty() && result.getCount() < 24) {
- final File file = pending.removeFirst();
+ final File file = pending.remove(0);
if (shouldHide(file)) continue;
if (file.isDirectory()) {
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index b786526ce676..828e5cf1fd4c 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -183,7 +183,7 @@ public class OverlayConfig {
final ParsedOverlayInfo p = partitionOverlayInfos.get(j);
if (p.isStatic) {
partitionConfigs.add(new ParsedConfiguration(p.packageName,
- true /* enabled */, false /* mutable */, partition.policy, p));
+ true /* enabled */, false /* mutable */, partition.policy, p, null));
}
}
diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java
index 0ab7b3d2ef86..5ab77d8d3236 100644
--- a/core/java/com/android/internal/content/om/OverlayConfigParser.java
+++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackagePartitions;
import android.content.pm.PackagePartitions.SystemPartition;
+import android.os.Build;
import android.os.FileUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -56,6 +57,34 @@ import java.util.Map;
**/
final class OverlayConfigParser {
+ /** Represents a part of a parsed overlay configuration XML file. */
+ public static class ParsedConfigFile {
+ @NonNull public final String path;
+ @NonNull public final int line;
+ @Nullable public final String xml;
+
+ ParsedConfigFile(@NonNull String path, int line, @Nullable String xml) {
+ this.path = path;
+ this.line = line;
+ this.xml = xml;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+ sb.append("{path=");
+ sb.append(path);
+ sb.append(", line=");
+ sb.append(line);
+ if (xml != null) {
+ sb.append(", xml=");
+ sb.append(xml);
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+ }
+
// Default values for overlay configurations.
static final boolean DEFAULT_ENABLED_STATE = false;
static final boolean DEFAULT_MUTABILITY = true;
@@ -94,24 +123,40 @@ final class OverlayConfigParser {
@NonNull
public final String policy;
- /** Information extracted from the manifest of the overlay. */
- @NonNull
+ /**
+ * Information extracted from the manifest of the overlay.
+ * Null if the information was read from a config file instead of a manifest.
+ *
+ * @see parsedConfigFile
+ **/
+ @Nullable
public final ParsedOverlayInfo parsedInfo;
+ /**
+ * The config file used to configure this overlay.
+ * Null if no config file was used, in which case the overlay's manifest was used instead.
+ *
+ * @see parsedInfo
+ **/
+ @Nullable
+ public final ParsedConfigFile parsedConfigFile;
+
ParsedConfiguration(@NonNull String packageName, boolean enabled, boolean mutable,
- @NonNull String policy, @NonNull ParsedOverlayInfo parsedInfo) {
+ @NonNull String policy, @Nullable ParsedOverlayInfo parsedInfo,
+ @Nullable ParsedConfigFile parsedConfigFile) {
this.packageName = packageName;
this.enabled = enabled;
this.mutable = mutable;
this.policy = policy;
this.parsedInfo = parsedInfo;
+ this.parsedConfigFile = parsedConfigFile;
}
@Override
public String toString() {
return getClass().getSimpleName() + String.format("{packageName=%s, enabled=%s"
- + ", mutable=%s, policy=%s, parsedInfo=%s}", packageName, enabled,
- mutable, policy, parsedInfo);
+ + ", mutable=%s, policy=%s, parsedInfo=%s, parsedConfigFile=%s}",
+ packageName, enabled, mutable, policy, parsedInfo, parsedConfigFile);
}
}
@@ -417,9 +462,26 @@ final class OverlayConfigParser {
Log.w(TAG, "found default-disabled immutable overlay " + packageName);
}
- final ParsedConfiguration Config = new ParsedConfiguration(packageName, isEnabled,
- isMutable, parsingContext.mPartition.policy, info);
+ final ParsedConfigFile parsedConfigFile = new ParsedConfigFile(
+ configFile.getPath().intern(), parser.getLineNumber(),
+ (Build.IS_ENG || Build.IS_USERDEBUG) ? currentParserContextToString(parser) : null);
+ final ParsedConfiguration config = new ParsedConfiguration(packageName, isEnabled,
+ isMutable, parsingContext.mPartition.policy, info, parsedConfigFile);
parsingContext.mConfiguredOverlays.add(packageName);
- parsingContext.mOrderedConfigurations.add(Config);
+ parsingContext.mOrderedConfigurations.add(config);
+ }
+
+ private static String currentParserContextToString(@NonNull XmlPullParser parser) {
+ StringBuilder sb = new StringBuilder("<");
+ sb.append(parser.getName());
+ sb.append(" ");
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ sb.append(parser.getAttributeName(i));
+ sb.append("=\"");
+ sb.append(parser.getAttributeValue(i));
+ sb.append("\" ");
+ }
+ sb.append("/>");
+ return sb.toString();
}
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 2ee47b64b1a5..4babb7080176 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -34,7 +34,7 @@ oneway interface IInputMethodPrivilegedOperations {
void setInputMethod(String id, in AndroidFuture future /* T=Void */);
void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
in AndroidFuture future /* T=Void */);
- void hideMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+ void hideMySoftInput(int flags, int reason, in AndroidFuture future /* T=Void */);
void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
void updateStatusIconAsync(String packageName, int iconId);
void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index d6697684f79e..97ad0840fbd5 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -194,12 +194,12 @@ public final class InputMethodDebug {
return "SHOW_SOFT_INPUT";
case SoftInputShowHideReason.ATTACH_NEW_INPUT:
return "ATTACH_NEW_INPUT";
- case SoftInputShowHideReason.SHOW_MY_SOFT_INPUT:
- return "SHOW_MY_SOFT_INPUT";
+ case SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME:
+ return "SHOW_SOFT_INPUT_FROM_IME";
case SoftInputShowHideReason.HIDE_SOFT_INPUT:
return "HIDE_SOFT_INPUT";
- case SoftInputShowHideReason.HIDE_MY_SOFT_INPUT:
- return "HIDE_MY_SOFT_INPUT";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME:
+ return "HIDE_SOFT_INPUT_FROM_IME";
case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV:
return "SHOW_AUTO_EDITOR_FORWARD_NAV";
case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV:
@@ -242,6 +242,16 @@ public final class InputMethodDebug {
return "SHOW_SOFT_INPUT_BY_INSETS_API";
case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE:
return "HIDE_DISPLAY_IME_POLICY_HIDE";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API:
+ return "HIDE_SOFT_INPUT_BY_INSETS_API";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY:
+ return "HIDE_SOFT_INPUT_BY_BACK_KEY";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT:
+ return "HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED:
+ return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION:
+ return "HIDE_SOFT_INPUT_IMM_DEPRECATION";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 15d7acfb6e0a..67c2103450bb 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -253,18 +253,19 @@ public final class InputMethodPrivilegedOperations {
* Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, IVoidResultCallback)}
*
* @param flags additional operating flags
+ * @param reason the reason to hide soft input
* @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
* @see android.view.inputmethod.InputMethodManager#HIDE_NOT_ALWAYS
*/
@AnyThread
- public void hideMySoftInput(int flags) {
+ public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
}
try {
final AndroidFuture<Void> future = new AndroidFuture<>();
- ops.hideMySoftInput(flags, future);
+ ops.hideMySoftInput(flags, reason, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 9e5776292031..97ad5cb4663c 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -19,8 +19,11 @@ package com.android.internal.inputmethod;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.os.IBinder;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import java.lang.annotation.Retention;
@@ -31,9 +34,9 @@ import java.lang.annotation.Retention;
@IntDef(value = {
SoftInputShowHideReason.SHOW_SOFT_INPUT,
SoftInputShowHideReason.ATTACH_NEW_INPUT,
- SoftInputShowHideReason.SHOW_MY_SOFT_INPUT,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME,
SoftInputShowHideReason.HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_MY_SOFT_INPUT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME,
SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV,
SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV,
SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE,
@@ -55,7 +58,12 @@ import java.lang.annotation.Retention;
SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT,
SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT,
SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
- SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE})
+ SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION})
public @interface SoftInputShowHideReason {
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
int SHOW_SOFT_INPUT = 0;
@@ -63,8 +71,12 @@ public @interface SoftInputShowHideReason {
/** Show soft input when {@code InputMethodManagerService#attachNewInputLocked} called. */
int ATTACH_NEW_INPUT = 1;
- /** Show soft input by {@code InputMethodManagerService#showMySoftInput}. */
- int SHOW_MY_SOFT_INPUT = 2;
+ /** Show soft input by {@code InputMethodManagerService#showMySoftInput}. This is triggered when
+ * the IME process try to show the keyboard.
+ *
+ * @see android.inputmethodservice.InputMethodService#requestShowSelf(int)
+ */
+ int SHOW_SOFT_INPUT_FROM_IME = 2;
/**
* Hide soft input by
@@ -72,8 +84,11 @@ public @interface SoftInputShowHideReason {
*/
int HIDE_SOFT_INPUT = 3;
- /** Hide soft input by {@code InputMethodManagerService#hideMySoftInput}. */
- int HIDE_MY_SOFT_INPUT = 4;
+ /**
+ * Hide soft input by
+ * {@link android.inputmethodservice.InputMethodService#requestHideSelf(int)}.
+ */
+ int HIDE_SOFT_INPUT_FROM_IME = 4;
/**
* Show soft input when navigated forward to the window (with
@@ -203,4 +218,32 @@ public @interface SoftInputShowHideReason {
* See also {@code InputMethodManagerService#mImeHiddenByDisplayPolicy}.
*/
int HIDE_DISPLAY_IME_POLICY_HIDE = 26;
+
+ /**
+ * Hide soft input by {@link android.view.InsetsController#hide(int)}.
+ */
+ int HIDE_SOFT_INPUT_BY_INSETS_API = 27;
+
+ /**
+ * Hide soft input by {@link android.inputmethodservice.InputMethodService#handleBack(boolean)}.
+ */
+ int HIDE_SOFT_INPUT_BY_BACK_KEY = 28;
+
+ /**
+ * Hide soft input by
+ * {@link android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)}.
+ */
+ int HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT = 29;
+
+ /**
+ * Hide soft input by
+ * {@link android.inputmethodservice.InputMethodService#onExtractingInputChanged(EditorInfo)})}.
+ */
+ int HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED = 30;
+
+ /**
+ * Hide soft input by the deprecated
+ * {@link InputMethodManager#hideSoftInputFromInputMethod(IBinder, int)}.
+ */
+ int HIDE_SOFT_INPUT_IMM_DEPRECATION = 31;
}
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 6fe1d8140371..684864638e90 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -206,6 +206,10 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
try {
Looper.prepare();
synchronized (this) {
+ if (mRenderer == null) {
+ // This can happen if 'releaseRenderer' is called immediately after 'start'.
+ return;
+ }
mChoreographer = Choreographer.getInstance();
}
Looper.loop();
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f727d80bba12..e258fc19a75f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -914,6 +914,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ if (!st.hasPanelItems()) {
+ // Ensure that |st.decorView| has its actual content. Otherwise, an empty window can be
+ // created and cause ANR.
+ return;
+ }
+
st.isHandled = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 377dfd0fb137..295dc545ef4b 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -258,11 +259,17 @@ public class TransitionAnimation {
}
return null;
}
-
- /** Load animation by attribute Id from a specific AnimationStyle resource. */
+ /**
+ * Load animation by attribute Id from a specific AnimationStyle resource.
+ *
+ * @param translucent {@code true} if we're sure that the animation is applied on a translucent
+ * window container, {@code false} otherwise.
+ * @param transit {@link TransitionOldType} for the app transition of this animation, or
+ * {@link TransitionOldType#TRANSIT_OLD_UNSET} if app transition type is unknown.
+ */
@Nullable
- public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
- boolean translucent) {
+ private Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
+ boolean translucent, @TransitionOldType int transit) {
if (animStyleResId == 0) {
return null;
}
@@ -278,6 +285,8 @@ public class TransitionAnimation {
}
if (translucent) {
resId = updateToTranslucentAnimIfNeeded(resId);
+ } else if (transit != TRANSIT_OLD_UNSET) {
+ resId = updateToTranslucentAnimIfNeeded(resId, transit);
}
if (ResourceId.isValid(resId)) {
return loadAnimationSafely(context, resId, mTag);
@@ -285,6 +294,15 @@ public class TransitionAnimation {
return null;
}
+
+ /** Load animation by attribute Id from a specific AnimationStyle resource. */
+ @Nullable
+ public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
+ boolean translucent) {
+ return loadAnimationAttr(packageName, animStyleResId, animAttr, translucent,
+ TRANSIT_OLD_UNSET);
+ }
+
/** Load animation by attribute Id from android package. */
@Nullable
public Animation loadDefaultAnimationAttr(int animAttr, boolean translucent) {
@@ -292,6 +310,13 @@ public class TransitionAnimation {
translucent);
}
+ /** Load animation by attribute Id from android package. */
+ @Nullable
+ public Animation loadDefaultAnimationAttr(int animAttr, @TransitionOldType int transit) {
+ return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
+ false /* translucent */, transit);
+ }
+
@Nullable
private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
if (mDebug) {
diff --git a/core/java/com/android/internal/usb/OWNERS b/core/java/com/android/internal/usb/OWNERS
new file mode 100644
index 000000000000..f7b2a37a297a
--- /dev/null
+++ b/core/java/com/android/internal/usb/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 1fd04109ae45..6eae34bf1999 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -331,6 +331,16 @@ public class ArrayUtils {
return array;
}
+ @NonNull
+ public static int[] convertToIntArray(@NonNull ArraySet<Integer> set) {
+ final int size = set.size();
+ int[] array = new int[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = set.valueAt(i);
+ }
+ return array;
+ }
+
public static @Nullable long[] convertToLongArray(@Nullable int[] intArray) {
if (intArray == null) return null;
long[] array = new long[intArray.length];
diff --git a/core/java/com/android/internal/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java
index 52306f1f877e..13ddc0602609 100644
--- a/core/java/com/android/internal/util/VirtualRefBasePtr.java
+++ b/core/java/com/android/internal/util/VirtualRefBasePtr.java
@@ -18,9 +18,12 @@ package com.android.internal.util;
/**
* Helper class that contains a strong reference to a VirtualRefBase native
- * object. This will incStrong in the ctor, and decStrong in the finalizer
+ * object. This will incStrong in the ctor, and decStrong in the finalizer.
+ * It currently does no accounting of natively allocated memory, for the
+ * benefit of either GC triggering or heap profiling.
*/
public final class VirtualRefBasePtr {
+ // TODO(b/231729094): Convert to NativeAllocationRegistry?
private long mNativePtr;
public VirtualRefBasePtr(long ptr) {
@@ -28,6 +31,14 @@ public final class VirtualRefBasePtr {
nIncStrong(mNativePtr);
}
+ /*
+ * Return the RefBase / VirtualLightRefBase native pointer. Warning: The
+ * caller must ensure that the VirtualRefBasePtr object remains reachable
+ * while the result is in use. Ideally, the caller should invoke
+ * {@link java.lang.ref.Reference#reachabilityFence}
+ * on the VirtualRefBasePtr object (or on an object that refers to it) as
+ * soon as the result is no longer needed.
+ */
public long get() {
return mNativePtr;
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 315776045afe..afe92a168fed 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -90,4 +90,6 @@ interface IInputMethodManager {
/** Start Stylus handwriting session **/
void startStylusHandwriting(in IInputMethodClient client);
+ /** Returns {@code true} if currently selected IME supports Stylus handwriting. */
+ boolean isStylusHandwritingAvailable();
}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index bf3e8d56b6bc..a0f7905771a2 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -1,11 +1,5 @@
package com.android.internal.view.menu;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
import android.annotation.AttrRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -22,16 +16,16 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewTreeObserver;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnKeyListener;
+import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.HeaderViewListAdapter;
import android.widget.ListAdapter;
-import android.widget.MenuItemHoverListener;
import android.widget.ListView;
+import android.widget.MenuItemHoverListener;
import android.widget.MenuPopupWindow;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
@@ -40,6 +34,11 @@ import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* A popup for a menu which will allow multiple submenus to appear in a cascading fashion, side by
* side.
@@ -70,7 +69,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
private final Handler mSubMenuHoverHandler;
/** List of menus that were added before this popup was shown. */
- private final List<MenuBuilder> mPendingMenus = new LinkedList<>();
+ private final List<MenuBuilder> mPendingMenus = new ArrayList<>();
/**
* List of open menus. The first item is the root menu and each
diff --git a/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java
index 481183e700a2..c1e2840f0a8b 100644
--- a/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java
+++ b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java
@@ -23,6 +23,7 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -96,7 +97,7 @@ public class ConversationHeaderLinearLayout extends LinearLayout {
continue;
}
if (visibleChildrenToShorten == null) {
- visibleChildrenToShorten = new LinkedList<>();
+ visibleChildrenToShorten = new ArrayList<>(count);
}
visibleChildrenToShorten.add(new ViewInfo(child));
remainingWeight += Math.max(0, weight);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a94b30707604..6771cdf84717 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -39,7 +39,6 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -47,7 +46,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index 8e68be0f742a..d068a3a0f62e 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -1,4 +1,4 @@
-per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
+per-file PointerLocationView.java = file:/INPUT_OWNERS
per-file RecyclerView.java = mount@google.com
per-file ViewPager.java = mount@google.com
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
index c484525dbe20..f7af67b3b2a8 100644
--- a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.view.MenuItem;
import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
import android.widget.PopupWindow;
import java.util.List;
@@ -92,7 +93,10 @@ public interface FloatingToolbarPopup {
* enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
*/
static FloatingToolbarPopup createInstance(Context context, View parent) {
- return new LocalFloatingToolbarPopup(context, parent);
+ boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
+ return enabled
+ ? new RemoteFloatingToolbarPopup(context, parent)
+ : new LocalFloatingToolbarPopup(context, parent);
}
}
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
index 8c61a12b47e6..95a4e1238e06 100644
--- a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
@@ -61,10 +61,10 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -950,9 +950,9 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
int availableWidth = toolbarWidth;
- final LinkedList<MenuItem> remainingMenuItems = new LinkedList<>();
+ final ArrayList<MenuItem> remainingMenuItems = new ArrayList<>();
// add the overflow menu items to the end of the remainingMenuItems list.
- final LinkedList<MenuItem> overflowMenuItems = new LinkedList();
+ final ArrayList<MenuItem> overflowMenuItems = new ArrayList<>();
for (MenuItem menuItem : menuItems) {
if (menuItem.getItemId() != android.R.id.textAssist
&& menuItem.requiresOverflow()) {
@@ -969,7 +969,7 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
int lastGroupId = -1;
boolean isFirstItem = true;
while (!remainingMenuItems.isEmpty()) {
- final MenuItem menuItem = remainingMenuItems.peek();
+ final MenuItem menuItem = remainingMenuItems.get(0);
// if this is the first item, regardless of requiresOverflow(), it should be
// displayed on the main panel. Otherwise all items including this one will be
@@ -1022,7 +1022,7 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
params.width = menuItemButtonWidth;
menuItemButton.setLayoutParams(params);
availableWidth -= menuItemButtonWidth;
- remainingMenuItems.pop();
+ remainingMenuItems.remove(0);
} else {
break;
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index eba6cca76389..817b3154889b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -676,7 +676,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
- char voldDecryptBuf[PROPERTY_VALUE_MAX];
char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
char perfettoJavaHeapStackOptBuf[
sizeof("-XX:PerfettoJavaHeapStackProf=") + PROPERTY_VALUE_MAX];
@@ -958,19 +957,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
addOption("-Xint:jit");
}
- // If we are booting without the real /data, don't spend time compiling.
- property_get("vold.decrypt", voldDecryptBuf, "");
- bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
- (strcmp(voldDecryptBuf, "1") == 0));
-
// Extra options for JIT.
- if (skip_compilation) {
- addOption("-Xcompiler-option");
- addOption("--compiler-filter=assume-verified");
- } else {
- parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
- "--compiler-filter=", "-Xcompiler-option");
- }
+ parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
+ "--compiler-filter=", "-Xcompiler-option");
parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=",
"-Xcompiler-option");
@@ -1011,52 +1000,48 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
parseExtraOpts(extraOptsBuf, NULL);
// Extra options for boot image generation.
- if (skip_compilation) {
- addOption("-Xnoimage-dex2oat");
- } else {
- parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
- "-Xms", "-Ximage-compiler-option");
- parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
- "-Xmx", "-Ximage-compiler-option");
-
- parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
- "--compiler-filter=", "-Ximage-compiler-option");
-
- // If there is a dirty-image-objects file, push it.
- if (hasFile("/system/etc/dirty-image-objects")) {
- addOption("-Ximage-compiler-option");
- addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
- }
+ parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
+ "-Xms", "-Ximage-compiler-option");
+ parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
+ "-Xmx", "-Ximage-compiler-option");
+
+ parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
+ "--compiler-filter=", "-Ximage-compiler-option");
+
+ // If there is a dirty-image-objects file, push it.
+ if (hasFile("/system/etc/dirty-image-objects")) {
+ addOption("-Ximage-compiler-option");
+ addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
+ }
- parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
- "-Ximage-compiler-option");
- parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
- "-Ximage-compiler-option");
-
- // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
- // to pass the instruction-set-features/variant as an image-compiler-option.
- // Note: it is OK to reuse the buffer, as the values are exactly the same between
- // * compiler-option, used for runtime compilation (DexClassLoader)
- // * image-compiler-option, used for boot-image compilation on device
- parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
- "--instruction-set-variant=", "-Ximage-compiler-option");
- parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
- "--instruction-set-features=", "-Ximage-compiler-option");
-
- if (generate_debug_info) {
- addOption("-Ximage-compiler-option");
- addOption("--generate-debug-info");
- }
+ parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
+ "-Ximage-compiler-option");
+ parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
+ "-Ximage-compiler-option");
- if (generate_mini_debug_info) {
- addOption("-Ximage-compiler-option");
- addOption("--generate-mini-debug-info");
- }
+ // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
+ // to pass the instruction-set-features/variant as an image-compiler-option.
+ // Note: it is OK to reuse the buffer, as the values are exactly the same between
+ // * compiler-option, used for runtime compilation (DexClassLoader)
+ // * image-compiler-option, used for boot-image compilation on device
+ parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
+ "--instruction-set-variant=", "-Ximage-compiler-option");
+ parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
+ "--instruction-set-features=", "-Ximage-compiler-option");
- property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
- parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
+ if (generate_debug_info) {
+ addOption("-Ximage-compiler-option");
+ addOption("--generate-debug-info");
}
+ if (generate_mini_debug_info) {
+ addOption("-Ximage-compiler-option");
+ addOption("--generate-mini-debug-info");
+ }
+
+ property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
+ parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
+
/* Set the properties for locale */
{
strcpy(localeOption, "-Duser.locale=");
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index ac6b80f6d4a3..96e9cc1c97f5 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -69,6 +69,7 @@ per-file com_android_internal_net_* = file:/services/core/java/com/android/serve
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_HardwareBuffer.cpp = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_SyncFence.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file android_os_GraphicsEnvironment.cpp = file:platform/frameworks/native:/opengl/OWNERS
### Text ###
per-file android_text_* = file:/core/java/android/text/OWNERS
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 8012e0c5ac57..30333d20d775 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -161,13 +161,13 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
return (jint) AUDIO_JAVA_ERROR;
}
- jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
+ jint* nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
return (jint) AUDIO_JAVA_ERROR;
}
audio_session_t sessionId = (audio_session_t) nSession[0];
- env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
+ env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
nSession = NULL;
sp<AudioRecord> lpRecorder;
@@ -288,14 +288,14 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
// callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
}
- nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
+ nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
goto native_init_failure;
}
// read the audio session ID back from AudioRecord in case a new session was created during set()
nSession[0] = lpRecorder->getSessionId();
- env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
+ env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
nSession = NULL;
{
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1afd2effef08..ae45a0e7763f 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -260,13 +260,13 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
- jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
+ jint* nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
if (nSession == NULL) {
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
return (jint) AUDIO_JAVA_ERROR;
}
audio_session_t sessionId = (audio_session_t) nSession[0];
- env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
+ env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
nSession = NULL;
@@ -458,14 +458,14 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
javaAudioTrackFields.postNativeEventInJava);
lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
- nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
+ nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
if (nSession == NULL) {
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
goto native_init_failure;
}
// read the audio session ID back from AudioTrack in case we create a new session
nSession[0] = lpTrack->getSessionId();
- env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
+ env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
nSession = NULL;
{
@@ -490,7 +490,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
// failures:
native_init_failure:
if (nSession != NULL) {
- env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
+ env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
}
setFieldSp(env, thiz, sp<AudioTrack>{}, javaAudioTrackFields.nativeTrackInJavaObj);
@@ -1022,14 +1022,15 @@ static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, j
AudioTimestamp timestamp;
status_t status = lpTrack->getTimestamp(timestamp);
if (status == OK) {
- jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
+ jlong* nTimestamp = env->GetLongArrayElements(jTimestamp, nullptr /* isCopy */);
if (nTimestamp == NULL) {
ALOGE("Unable to get array for getTimestamp()");
return (jint)AUDIO_JAVA_ERROR;
}
- nTimestamp[0] = (jlong) timestamp.mPosition;
- nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
- env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
+ nTimestamp[0] = static_cast<jlong>(timestamp.mPosition);
+ nTimestamp[1] = static_cast<jlong>((timestamp.mTime.tv_sec * 1000000000LL) +
+ timestamp.mTime.tv_nsec);
+ env->ReleaseLongArrayElements(jTimestamp, nTimestamp, 0 /* mode */);
}
return (jint) nativeToJavaStatus(status);
}
@@ -1338,14 +1339,14 @@ static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env,
ALOGE("%s: AudioTrack not initialized", __func__);
return (jint)AUDIO_JAVA_ERROR;
}
- jfloat *nativeLevel = (jfloat *)env->GetPrimitiveArrayCritical(level, NULL);
+ jfloat *nativeLevel = env->GetFloatArrayElements(level, nullptr /* isCopy */);
if (nativeLevel == nullptr) {
ALOGE("%s: Cannot retrieve level pointer", __func__);
return (jint)AUDIO_JAVA_ERROR;
}
status_t status = lpTrack->getAudioDescriptionMixLevel(reinterpret_cast<float *>(nativeLevel));
- env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
+ env->ReleaseFloatArrayElements(level, nativeLevel, 0 /* mode */);
return nativeToJavaStatus(status);
}
@@ -1368,7 +1369,7 @@ static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
ALOGE("%s: AudioTrack not initialized", __func__);
return (jint)AUDIO_JAVA_ERROR;
}
- jint *nativeDualMonoMode = (jint *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
+ jint *nativeDualMonoMode = env->GetIntArrayElements(dualMonoMode, nullptr /* isCopy */);
if (nativeDualMonoMode == nullptr) {
ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
return (jint)AUDIO_JAVA_ERROR;
@@ -1376,7 +1377,7 @@ static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
status_t status = lpTrack->getDualMonoMode(
reinterpret_cast<audio_dual_mono_mode_t *>(nativeDualMonoMode));
- env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
+ env->ReleaseIntArrayElements(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
return nativeToJavaStatus(status);
}
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index f44e829d49d7..78e2d3164993 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,7 +50,7 @@ void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName,
}
void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
- jstring devOptIn, jobjectArray featuresObj) {
+ jboolean angleIsSystemDriver, jstring devOptIn, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars devOptInChars(env, devOptIn);
@@ -74,7 +74,18 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa
}
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptInChars.c_str(), features);
+ angleIsSystemDriver, devOptInChars.c_str(),
+ features);
+}
+
+void setLegacyDriverInfo_native(JNIEnv* env, jobject clazz, jstring appName,
+ jboolean angleIsSystemDriver, jstring legacyDriverName) {
+ ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars legacyDriverNameChars(env, legacyDriverName);
+
+ android::GraphicsEnv::getInstance().setLegacyDriverInfo(appNameChars.c_str(),
+ angleIsSystemDriver,
+ legacyDriverNameChars.c_str());
}
bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -120,8 +131,10 @@ const JNINativeMethod g_methods[] = {
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
{"setAngleInfo",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
+ "(Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
+ {"setLegacyDriverInfo", "(Ljava/lang/String;ZLjava/lang/String;)V",
+ reinterpret_cast<void*>(setLegacyDriverInfo_native)},
{"getShouldUseAngle", "(Ljava/lang/String;)Z",
reinterpret_cast<void*>(shouldUseAngle_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 734b6ca47660..1c61c7be4414 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -82,9 +82,8 @@ static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass,
});
}
-static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass, jlong tag,
- jstring trackStr, jstring nameStr,
- jint cookie) {
+static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass,
+ jlong tag, jstring trackStr, jstring nameStr, jint cookie) {
withString(env, trackStr, [env, tag, nameStr, cookie](char* track) {
withString(env, nameStr, [tag, track, cookie](char* name) {
atrace_async_for_track_begin(tag, track, name, cookie);
@@ -92,13 +91,10 @@ static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass,
});
}
-static void android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv* env, jclass, jlong tag,
- jstring trackStr, jstring nameStr,
- jint cookie) {
- withString(env, trackStr, [env, tag, nameStr, cookie](char* track) {
- withString(env, nameStr, [tag, track, cookie](char* name) {
- atrace_async_for_track_end(tag, track, name, cookie);
- });
+static void android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv* env, jclass,
+ jlong tag, jstring trackStr, jint cookie) {
+ withString(env, trackStr, [tag, cookie](char* track) {
+ atrace_async_for_track_end(tag, track, cookie);
});
}
@@ -156,7 +152,7 @@ static const JNINativeMethod gTraceMethods[] = {
"(JLjava/lang/String;Ljava/lang/String;I)V",
(void*)android_os_Trace_nativeAsyncTraceForTrackBegin },
{ "nativeAsyncTraceForTrackEnd",
- "(JLjava/lang/String;Ljava/lang/String;I)V",
+ "(JLjava/lang/String;I)V",
(void*)android_os_Trace_nativeAsyncTraceForTrackEnd },
{ "nativeInstant",
"(JLjava/lang/String;)V",
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 9098d46ee29c..d73db6245672 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -24,8 +24,18 @@
namespace android {
-// Converstion to/from Java IBinder Object and C++ IBinder instance.
+/**
+ * Conversion to Java IBinder Object from C++ IBinder instance.
+ *
+ * WARNING: this function returns global and local references. This can be
+ * figured out using GetObjectRefType. Though, when this function is called
+ * from within a Java context, the local ref will automatically be cleaned
+ * up. If this is called outside of a Java frame,
+ * PushObjectFrame/PopObjectFrame can simulate this automatic cleanup. The
+ * platform provides ScopedLocalFrame as an RAII object for this.
+ */
extern jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+/** Conversion from Java IBinder Object to C++ IBinder instance. */
extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 05855867ed62..c9110d144018 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -90,8 +90,9 @@ NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject rece
const sp<MessageQueue>& messageQueue,
jint vsyncSource, jint eventRegistration)
: DisplayEventDispatcher(messageQueue->getLooper(),
- static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
- static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
+ static_cast<gui::ISurfaceComposer::VsyncSource>(vsyncSource),
+ static_cast<gui::ISurfaceComposer::EventRegistration>(
+ eventRegistration)),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index f388fec2cd78..8483a152241a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1962,8 +1962,10 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac
jlong frameTimelineVsyncId) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- transaction->setFrameTimelineInfo(
- {frameTimelineVsyncId, android::os::IInputConstants::INVALID_INPUT_EVENT_ID});
+ FrameTimelineInfo ftInfo;
+ ftInfo.vsyncId = frameTimelineVsyncId;
+ ftInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
+ transaction->setFrameTimelineInfo(ftInfo);
}
static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2048,7 +2050,7 @@ static jlong nativeCreateJankDataListenerWrapper(JNIEnv* env, jclass clazz,
}
static jint nativeGetGPUContextPriority(JNIEnv* env, jclass clazz) {
- return static_cast<jint>(SurfaceComposerClient::getGPUContextPriority());
+ return static_cast<jint>(SurfaceComposerClient::getGpuContextPriority());
}
static void nativeSetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 21bbac0b0a7d..34fd478baeda 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1153,8 +1153,8 @@ static void relabelDir(const char* path, const char* context, fail_fn_t fail_fn)
}
}
-// Relabel all directories under a path non-recursively.
-static void relabelAllDirs(const char* path, const char* context, fail_fn_t fail_fn) {
+// Relabel the subdirectories and symlinks in the given directory, non-recursively.
+static void relabelSubdirs(const char* path, const char* context, fail_fn_t fail_fn) {
DIR* dir = opendir(path);
if (dir == nullptr) {
fail_fn(CREATE_ERROR("Failed to opendir %s", path));
@@ -1177,38 +1177,40 @@ static void relabelAllDirs(const char* path, const char* context, fail_fn_t fail
}
/**
- * Make other apps data directory not visible in CE, DE storage.
+ * Hide the CE and DE data directories of non-related apps.
*
- * Apps without app data isolation can detect if another app is installed on system,
- * by "touching" other apps data directory like /data/data/com.whatsapp, if it returns
- * "Permission denied" it means apps installed, otherwise it returns "File not found".
- * Traditional file permissions or SELinux can only block accessing those directories but
- * can't fix fingerprinting like this.
- * We fix it by "overlaying" data directory, and only relevant app data packages exists
- * in data directories.
+ * Without this, apps can detect if any app is installed by trying to "touch" the app's CE
+ * or DE data directory, e.g. /data/data/com.whatsapp. This fails with EACCES if the app
+ * is installed, or ENOENT if it's not. Traditional file permissions or SELinux can only
+ * block accessing those directories but can't fix fingerprinting like this.
*
- * Steps:
- * 1). Collect a list of all related apps (apps with same uid and allowlisted apps) data info
- * (package name, data stored volume uuid, and inode number of its CE data directory)
- * 2). Mount tmpfs on /data/data, /data/user(_de) and /mnt/expand, so apps no longer
- * able to access apps data directly.
- * 3). For each related app, create its app data directory and bind mount the actual content
- * from apps data mirror directory. This works on both CE and DE storage, as DE storage
- * is always available even storage is FBE locked, while we use inode number to find
- * the encrypted DE directory in mirror so we can still bind mount it successfully.
+ * Instead, we hide non-related apps' data directories from the filesystem entirely by
+ * mounting tmpfs instances over their parent directories and bind-mounting in just the
+ * needed app data directories. This is done in a private mount namespace.
*
- * Example:
- * 0). Assuming com.android.foo CE data is stored in /data/data and no shared uid
- * 1). Mount a tmpfs on /data/data, /data/user, /data/user_de, /mnt/expand
- * List = ["com.android.foo", "null" (volume uuid "null"=default),
- * 123456 (inode number)]
- * 2). On DE storage, we create a directory /data/user_de/0/com.com.android.foo, and bind
- * mount (in the app's mount namespace) it from /data_mirror/data_de/0/com.android.foo.
- * 3). We do similar for CE storage. But in direct boot mode, as /data_mirror/data_ce/0/ is
- * encrypted, we can't find a directory with name com.android.foo on it, so we will
- * use the inode number to find the right directory instead, which that directory content will
- * be decrypted after storage is decrypted.
+ * Steps:
+ * (1) Collect a list of all related apps (apps with same uid and allowlisted apps) data info
+ * (package name, data stored volume uuid, and inode number of its CE data directory)
+ * (2) Mount tmpfs on /data/data and /data/user{,_de}, and on /mnt/expand/$volume/user{,_de}
+ * for all adoptable storage volumes. This hides all app data directories.
+ * (3) For each related app, create stubs for its data directories in the relevant tmpfs
+ * instances, then bind mount in the actual directories from /data_mirror. This works
+ * for both the CE and DE directories. DE storage is always unlocked, whereas the
+ * app's CE directory can be found via inode number if CE storage is locked.
*
+ * Example assuming user 0, app "com.android.foo", no shared uid, and no adoptable storage:
+ * (1) Info = ["com.android.foo", "null" (volume uuid "null"=default), "123456" (inode number)]
+ * (2) Mount tmpfs on /data/data, /data/user, and /data/user_de.
+ * (3) For DE storage, create a directory /data/user_de/0/com.android.foo and bind mount
+ * /data_mirror/data_de/0/com.android.foo onto it.
+ * (4) Do similar for CE storage. But if the device is in direct boot mode, then CE
+ * storage will be locked, so the app's CE data directory won't exist at the usual
+ * path /data_mirror/data_ce/0/com.android.foo. It will still exist in
+ * /data_mirror/data_ce/0, but its filename will be an unpredictable no-key name. In
+ * this case, we use the inode number to find the right directory instead. Note that
+ * the bind-mounted app CE data directory will remain locked. It will be unlocked
+ * automatically if/when the user's CE storage is unlocked, since adding an encryption
+ * key takes effect on a whole filesystem instance including all its mounts.
*/
static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
uid_t uid, const char* process_name,
@@ -1229,11 +1231,19 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
snprintf(internalDePath, PATH_MAX, "/data/user_de");
snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
- char* dataDataContext = nullptr;
- if (getfilecon(internalDePath, &dataDataContext) < 0) {
- fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath,
+ // Get the "u:object_r:system_userdir_file:s0" security context. This can be
+ // gotten from several different places; we use /data/user.
+ char* dataUserdirContext = nullptr;
+ if (getfilecon(internalCePath, &dataUserdirContext) < 0) {
+ fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalCePath,
strerror(errno)));
}
+ // Get the "u:object_r:system_data_file:s0" security context. This can be
+ // gotten from several different places; we use /data/misc.
+ char* dataFileContext = nullptr;
+ if (getfilecon("/data/misc", &dataFileContext) < 0) {
+ fail_fn(CREATE_ERROR("Unable to getfilecon on /data/misc %s", strerror(errno)));
+ }
MountAppDataTmpFs(internalLegacyCePath, fail_fn);
MountAppDataTmpFs(internalCePath, fail_fn);
@@ -1328,19 +1338,19 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
// the file operations on tmpfs. If we set the label when we mount
// tmpfs, SELinux will not happy as we are changing system_data_files.
// Relabel dir under /data/user, including /data/user/0
- relabelAllDirs(internalCePath, dataDataContext, fail_fn);
+ relabelSubdirs(internalCePath, dataFileContext, fail_fn);
// Relabel /data/user
- relabelDir(internalCePath, dataDataContext, fail_fn);
+ relabelDir(internalCePath, dataUserdirContext, fail_fn);
// Relabel /data/data
- relabelDir(internalLegacyCePath, dataDataContext, fail_fn);
+ relabelDir(internalLegacyCePath, dataFileContext, fail_fn);
- // Relabel dir under /data/user_de
- relabelAllDirs(internalDePath, dataDataContext, fail_fn);
+ // Relabel subdirectories of /data/user_de
+ relabelSubdirs(internalDePath, dataFileContext, fail_fn);
// Relabel /data/user_de
- relabelDir(internalDePath, dataDataContext, fail_fn);
+ relabelDir(internalDePath, dataUserdirContext, fail_fn);
// Relabel CE and DE dirs under /mnt/expand
dir = opendir(externalPrivateMountPath);
@@ -1353,14 +1363,15 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
auto cePath = StringPrintf("%s/user", volPath.c_str());
auto dePath = StringPrintf("%s/user_de", volPath.c_str());
- relabelAllDirs(cePath.c_str(), dataDataContext, fail_fn);
- relabelDir(cePath.c_str(), dataDataContext, fail_fn);
- relabelAllDirs(dePath.c_str(), dataDataContext, fail_fn);
- relabelDir(dePath.c_str(), dataDataContext, fail_fn);
+ relabelSubdirs(cePath.c_str(), dataFileContext, fail_fn);
+ relabelDir(cePath.c_str(), dataUserdirContext, fail_fn);
+ relabelSubdirs(dePath.c_str(), dataFileContext, fail_fn);
+ relabelDir(dePath.c_str(), dataUserdirContext, fail_fn);
}
closedir(dir);
- freecon(dataDataContext);
+ freecon(dataUserdirContext);
+ freecon(dataFileContext);
}
static void insertPackagesToMergedList(JNIEnv* env,
@@ -1599,10 +1610,11 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
// since the directory is owned by root.
if (!is_system_server && getuid() == 0) {
const int rc = createProcessGroup(uid, getpid());
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else if (rc != 0) {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ if (rc != 0) {
+ fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
+ "CONFIG_CGROUP_CPUACCT?")
+ : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
+ /* pid= */ 0, strerror(-rc)));
}
}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index a4463e4e96c5..907093343a3f 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -16,6 +16,7 @@ roosa@google.com
per-file package_item_info.proto = toddke@google.com,patb@google.com
per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS
per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
+per-file android/hardware/sensorprivacy.proto = ntmyren@google.com,evanseverson@google.com,ewol@google.com
# Biometrics
jaggies@google.com
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 7e26952a92da..4f3eeb0733f4 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -434,8 +434,9 @@ message SystemPropertiesProto {
optional string vibrator = 37;
optional string virtual_device = 38;
optional string vulkan = 39;
+ optional string egl_legacy = 40;
- // Next Tag: 40
+ // Next Tag: 41
}
optional Hardware hardware = 27;
@@ -555,4 +556,3 @@ message SystemPropertiesProto {
// Next Tag: 32
}
-
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3c2a48a51b09..e165b079f450 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -468,6 +468,10 @@ message GlobalSettingsProto {
optional SettingProto updatable_driver_prerelease_opt_in_apps = 18;
optional SettingProto angle_egl_features = 19;
+ // ANGLE - List of Apps that ANGLE may have issues with
+ optional SettingProto angle_deferlist = 20;
+ // ANGLE - Integer mode of the logic for applying `angle_deferlist`
+ optional SettingProto angle_deferlist_mode = 21;
}
optional Gpu gpu = 59;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 7205dd817eb5..6ec71baa836a 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -91,6 +91,7 @@ message ReceiverListProto {
repeated BroadcastFilterProto filters = 7;
// Used to find this ReceiverList object in IntentResolver
optional string hex_hash = 8;
+ optional int32 number_receivers = 9;
}
message ProcessRecordProto {
diff --git a/core/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto
new file mode 100644
index 000000000000..9429127b2f6e
--- /dev/null
+++ b/core/proto/android/server/windowmanagertransitiontrace.proto
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package com.android.server.wm.shell;
+
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+
+option java_multiple_files = true;
+
+/* Represents a file full of transition entries.
+ Encoded, it should start with 0x9 0x57 0x49 0x4e 0x54 0x52 0x41 0x43 0x45 (.TRNTRACE), such
+ that it can be easily identified. */
+message TransitionTraceProto {
+
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x544e5254; /* TRNT (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ int64 timestamp = 2; /* The timestamp of when the trace was started. */
+ repeated Transition transition = 3;
+}
+
+message Transition {
+
+ enum State {
+ COLLECTING = 0;
+ PENDING = -1;
+ STARTED = 1;
+ PLAYING = 2;
+ ABORT = 3;
+ FINISHED = 4;
+ }
+
+ int32 id = 1;
+ int32 transition_type = 2;
+ int64 timestamp = 3;
+ State state = 5;
+ int32 flags = 6;
+ repeated ChangeInfo change = 7;
+}
+
+message ChangeInfo {
+ com.android.server.wm.IdentifierProto window_identifier = 1;
+ int32 transit_mode = 2;
+ bool has_changed = 3;
+ int32 change_flags = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e52da0fd6787..45beba2e0e3c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -142,6 +142,7 @@
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE" />
<protected-broadcast android:name="android.os.action.SETTING_RESTORED" />
@@ -563,7 +564,7 @@
<protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
<protected-broadcast android:name="com.android.server.action.NETWORK_STATS_POLL" />
<protected-broadcast android:name="com.android.server.action.NETWORK_STATS_UPDATED" />
- <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
+ <protected-broadcast android:name="com.android.server.timedetector.NetworkTimeUpdateService.action.POLL" />
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
<protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
@@ -2280,7 +2281,8 @@
android:protectionLevel="signature|role" />
<!-- Allows bluetooth stack to access files
- @hide This should only be used by Bluetooth apk.
+ This should only be granted to the Bluetooth apk.
+ @hide @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)
-->
<permission android:name="android.permission.BLUETOOTH_STACK"
android:protectionLevel="signature|role" />
@@ -4409,13 +4411,13 @@
<permission android:name="android.permission.TUNER_RESOURCE_ACCESS"
android:protectionLevel="signature|privileged|vendorPrivileged" />
- <!-- This permission is required by Media Resource Manager Service when
- accessing its overridePid Api.
- <p>Protection level: signature
+ <!-- @SystemApi This permission is required by Media Resource Manager Service when
+ system services create MediaCodecs on behalf of other processes and apps.
+ <p>Protection level: signature|privileged|vendorPrivileged
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
<!-- This permission is required by Media Resource Observer Service when
@@ -5614,6 +5616,10 @@
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="signature|privileged" />
+ <!-- Allows managing (adding, removing) face templates. Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_FACE"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
android:protectionLevel="signature" />
diff --git a/core/res/res/drawable/ic_test_badge_experiment.xml b/core/res/res/drawable/ic_test_badge_experiment.xml
new file mode 100644
index 000000000000..0eae03bb0974
--- /dev/null
+++ b/core/res/res/drawable/ic_test_badge_experiment.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2022 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="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M4.271,17.5Q3.167,17.5 2.688,16.51Q2.208,15.521 2.896,14.667L7.438,9.146V4.25H6.688Q6.312,4.25 6.062,4Q5.812,3.75 5.812,3.375Q5.812,3 6.062,2.75Q6.312,2.5 6.688,2.5H13.312Q13.688,2.5 13.938,2.75Q14.188,3 14.188,3.375Q14.188,3.75 13.938,4Q13.688,4.25 13.312,4.25H12.562V9.146L17.104,14.667Q17.792,15.521 17.312,16.51Q16.833,17.5 15.729,17.5ZM6.104,14.875H13.896L11.229,11.646H8.771ZM4.271,15.75H15.729L10.812,9.75V4.25H9.188V9.75ZM10,10Z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_test_badge_no_background.xml b/core/res/res/drawable/ic_test_badge_no_background.xml
new file mode 100644
index 000000000000..1f05da045ba9
--- /dev/null
+++ b/core/res/res/drawable/ic_test_badge_no_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2022 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M5,21Q3.725,21 3.188,19.863Q2.65,18.725 3.45,17.75L9,11V5H8Q7.575,5 7.287,4.712Q7,4.425 7,4Q7,3.575 7.287,3.287Q7.575,3 8,3H16Q16.425,3 16.712,3.287Q17,3.575 17,4Q17,4.425 16.712,4.712Q16.425,5 16,5H15V11L20.55,17.75Q21.35,18.725 20.812,19.863Q20.275,21 19,21ZM7,18H17L13.6,14H10.4ZM5,19H19L13,11.7V5H11V11.7ZM12,12Z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_test_icon_badge_experiment.xml b/core/res/res/drawable/ic_test_icon_badge_experiment.xml
new file mode 100644
index 000000000000..c37e2079a5ce
--- /dev/null
+++ b/core/res/res/drawable/ic_test_icon_badge_experiment.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2022 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="64dp"
+ android:height="64dp"
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M8.6,42Q6.55,42 5.8,39.9Q5.05,37.8 6.2,36.5L18.6,22.5V9H16Q15.4,9 14.95,8.55Q14.5,8.1 14.5,7.5Q14.5,6.9 14.95,6.45Q15.4,6 16,6H32Q32.6,6 33.05,6.45Q33.5,6.9 33.5,7.5Q33.5,8.1 33.05,8.55Q32.6,9 32,9H29.4V22.5L41.8,36.5Q43,37.85 42.225,39.925Q41.45,42 39.4,42ZM12.1,37.5H35.9L27.9,28.25H20.1ZM8,39H40L26.4,23.6V9H21.6V23.6ZM24,24Z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4370acd379c1..e8244c4e7217 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Vingerafdrukslot"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Kan nie vingerafdruksensor gebruik nie"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besoek \'n verskaffer wat herstelwerk doen."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Kon nie gesigdata akkuraat vasvang nie. Probeer weer."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan nie jou gesigmodel skep nie. Probeer weer."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Te helder. Probeer sagter beligting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Te donker. Probeer helderder beligting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Beweeg foon verder weg"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Beweeg foon nader."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Beweeg foon hoër op."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Beweeg foon laer af."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Beweeg foon na links."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Beweeg foon na regs."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer helderder beligting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Beweeg foon verder weg"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Beweeg foon nader"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Beweeg foon hoër op"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Beweeg foon laer af"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Beweeg foon na jou linkerkant"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Beweeg foon na jou regterkant"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Kyk asseblief meer reguit na jou toestel."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Posisioneer jou gesig direk voor die foon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kan nie jou gesig sien nie. Hou jou foon op oogvlak."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te veel beweging. Hou foon stil."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Skryf jou gesig asseblief weer in."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Kan nie meer gesig herken nie. Probeer weer."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Te eenders. Verander asseblief jou pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai jou kop \'n bietjie minder."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kantel jou kop \'n bietjie minder."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai jou kop \'n bietjie minder."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Kan nie gesig herken nie. Probeer weer."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Verander die posisie van jou kop effens"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kyk meer reguit na jou foon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kyk meer reguit na jou foon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Kyk meer reguit na jou foon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Verwyder enigiets wat jou gesig versteek."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Maak die bokant van jou skerm skoon, insluitend die swart balk"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Jou gesig moet heeltemal sigbaar wees"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Jou gesig moet heeltemal sigbaar wees"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Kan nie jou gesigmodel skep nie. Probeer weer."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Donkerbril bespeur. Jou gesig moet heeltemal sigbaar wees."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Gesigbedekking bespeur. Jou gesig moet heeltemal sigbaar wees."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan nie gesig verifieer nie. Hardeware nie beskikbaar nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8c6db331798f..b15d564fee71 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"በጣት አሻራ መክፈቻ"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"የጣት አሻራ ዳሳሽን መጠቀም አይቻልም"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"የጥገና አገልግሎት ሰጪን ይጎብኙ።"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ትክክለኛ የፊት ውሂብ ማንሳት አልተቻለም። እንደገና ይሞክሩ።"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"የመልክዎን ሞዴል መፍጠር አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ከልክ በላይ ፈካ ያለ። ይበልጥ ረጋ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ከልክ በላይ ጨለማ ነው። ከዚህ ፈካ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ስልክን ይበልጥ አርቀው ያንቀሳቅሱት።"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ስልክን ወደ ቅርብ ቦታ ያንቀሳቅሱ።"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ስልኩን ከፍ ወዳለ ቦታ ያንቀሳቅሱት።"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ስልክን ወደ ታች ዝቅ ያድርጉ።"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ስልክን ወደ ግራ ያንቀሳቅሱ።"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ስልክን ወደ ቀኝ ያንቀሳቅሱ።"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ከዚህ ፈካ ያለ ብርሃንን ይሞክሩ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ስልኩን ያርቁት"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ስልኩን ያቅርቡት"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ስልኩን ከፍ ወዳለ ቦታ ይውሰዱት"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ስልኩን ወደ ታች ዝቅ ያድርጉ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ስልክዎን ወደ በስተግራዎ ይውሰዱት"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ስልኩን ወደ በስተቀኝዎ ይውሰዱት"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"እባክዎ መሣሪያዎን ይበልጥ በቀጥታ ይመልከቱ።"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"መልክዎን በቀጥታ ከስልኩ ፊት ያድርጉት።"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"የእርስዎን መልክ ማየት አይችልም። ስልክዎን በዓይን ትክክል ይያዙ።"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ከልክ በላይ ብዙ እንቅስቃሴ። ስልኩን ቀጥ አድርገው ይያዙት።"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"እባክዎ ፊትዎን እንደገና ያስመዝግቡ"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"በጣም ይመሳሰላል፣ እባክዎ የእርስዎን ፎቶ አነሳስ ይለውጡ"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ጭንቅላትዎን ትንሽ ብቻ ያጋድሉት።"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"መልክን መለየት አልተቻለም። እንደገና ይሞክሩ።"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"የጭንቅላትዎን ቦታ በትንሹ ይለዋውጡ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ስልክዎን ይበልጥ በቀጥታ ይመልከቱ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ስልክዎን ይበልጥ በቀጥታ ይመልከቱ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ስልክዎን ይበልጥ በቀጥታ ይመልከቱ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"የእርስዎን ፊት የሚደብቀውን ሁሉንም ነገር በማስወገድ ላይ"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"የማያ ገጽዎን አናት ያጽዱት፣ ጥቁር አሞሌውን ጨምሮ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"መልክዎ ሙሉ በሙሉ መታየት አለበት"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"መልክዎ ሙሉ በሙሉ መታየት አለበት"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"የመልክዎን ሞዴል መፍጠር አልተቻለም። እንደገና ይሞክሩ።"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ጠቆር ያሉ መነጽሮች ተገኝተዋል። መልክዎ ሙሉ በሙሉ መታየት አለበት።"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"የመልክ መሸፈኛ ተገኝቷል። መልክዎ ሙሉ በሙሉ መታየት አለበት።"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"መልክን ማረጋገጥ አይቻልም። ሃርድዌር የለም።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index dceeb7392d51..41531ebd7f0d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -638,26 +638,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"فتح الجهاز ببصمة الإصبع"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"لا يمكن استخدام مستشعر بصمات الإصبع"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"يُرجى التواصل مع مقدِّم خدمات إصلاح."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"تعذّر تسجيل بيانات دقيقة للوجه. حاول مرة أخرى."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"يتعذّر إنشاء نموذج الوجه. يُرجى إعادة المحاولة."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ساطع للغاية. تجربة مستوى سطوع أقلّ."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"الصورة معتمة للغاية. يُرجى زيادة السطوع."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"يُرجى نقل الهاتف مسافة أبعد."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"انقل الهاتف إلى مكان قريب."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"يُرجى رفع الهاتف للأعلى."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"يُرجى خفض الهاتف للأسفل."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"يُرجى نقل الهاتف إلى اليمين."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"يُرجى نقل الهاتف إلى اليسار."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"جرِّب زيادة سطوع الشاشة."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"يُرجى إبعاد الهاتف عنك."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"يُرجى تقريب الهاتف منك."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"يُرجى رفع الهاتف للأعلى."</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"يُرجى خفض الهاتف للأسفل."</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"يُرجى تحريك الهاتف جهة اليسار."</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"يُرجى تحريك الهاتف جهة اليمين."</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"يُرجى النظر إلى جهازك مباشرة أكثر."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ضع وجهك أمام الهاتف مباشرة."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"تتعذّر رؤية وجهك. اِرفع هاتفك ليكون في مستوى العينَين."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"حركة أكثر من اللازم يُرجى حمل بدون حركة."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"يُرجى إعادة تسجيل وجهك."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"الوجه مشابه جدًا، يُرجى تغيير وضعيتك."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"يُرجى إمالة رأسك أقل قليلاً."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"حرّك رأسك قليلاً نحو الوسط."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"يتعذّر التعرّف على الوجه. يُرجى إعادة المحاولة."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"غيِّر موضع رأسك قليلاً."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"يُرجى النظر إلى هاتفك مباشرةً."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"يُرجى النظر إلى هاتفك مباشرةً."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"يُرجى النظر إلى هاتفك مباشرةً."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"عليك بإزالة أي شيء يُخفي وجهك."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"يُرجى تنظيف الجزء العلوي من الشاشة، بما في ذلك الشريط الأسود."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"يجب أن يكون وجهك ظاهرًا بالكامل."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"يجب أن يكون وجهك ظاهرًا بالكامل."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"يتعذّر إنشاء نموذج الوجه. يُرجى إعادة المحاولة."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"تمّ رصد نظارة شمسية. يجب أن يكون وجهك ظاهرًا بالكامل."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"تمّ رصد قناع على الوجه. يجب أن يكون وجهك ظاهرًا بالكامل."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"يتعذّر التحقُّق من الوجه. الجهاز غير مُتاح."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 09c1870feb40..28ca15636fed 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ফিংগাৰপ্ৰিন্ট আনলক"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰ ব্যৱহাৰ কৰিব নোৱাৰি"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"মেৰামতি সেৱা প্ৰদানকাৰী কোনো প্ৰতিষ্ঠানলৈ যাওক।"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"সঠিক মুখমণ্ডলৰ ডেটা কেপচাৰ নহ’ল। আকৌ চেষ্টা কৰক।"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"মুখাৱয়বৰ মডেল সৃষ্টি কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"অতি উজ্জ্বল। ইয়াতকৈ কম পোহৰৰ উৎস ব্যৱহাৰ কৰক।"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"অতি আন্ধাৰ। উজ্জ্বল লাইট ব্যৱহাৰ কৰক।"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ফ’নটো আৰু আঁতৰলৈ নিয়ক।"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ফ’নটো ওচৰলৈ আনক।"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ফ’নটো ওপৰলৈ নিয়ক।"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ফ’নটো তললৈ নিয়ক"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ফ’নটো বাওঁফালে নিয়ক।"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ফ’নটো সোঁফালে নিয়ক।"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"উজ্জ্বল পোহৰ থকা ঠাইলৈ গৈ চাওক"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ফ’নটো আৰু আঁতৰলৈ নিয়ক"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ফ’নটো ওচৰলৈ আনক"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ফ’নটো ওপৰলৈ নিয়ক"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ফ’নটো তললৈ নিয়ক"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ফ’নটো আপোনাৰ বাওঁফাললৈ নিয়ক"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ফ’নটো আপোনাৰ সোঁফাললৈ নিয়ক"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"আপোনাৰ ডিভাইচটোলৈ অধিক পোনে পোনে চাওক।"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"আপোনাৰ মুখখন পোনপটীয়াকৈ ফ’নটোৰ সন্মুখত ৰাখক।"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"আপোনাৰ মুখাৱয়ব দেখা নাই। আপোনাৰ ফ’নটো চকুৰ স্তৰত ধৰি ৰাখক।"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"বেছি লৰচৰ কৰি আছে। ফ’নটো স্থিৰকৈ ধৰক।"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ন কৰক।"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"একে ধৰণৰ হৈছে, অনুগ্ৰহ কৰি আপোনাৰ প’জটো সলনি কৰক।"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"আপোনাৰ মূৰটো অলপ কমকৈ হেলনীয়া কৰক।"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"মুখাৱয়ব চিনিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"আপোনাৰ মূৰটোৰ স্থান সামান্য সলনি কৰক"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"আপোনাৰ ফ’নটোলৈ আৰু পোনপটীয়াকৈ চাওক"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"আপোনাৰ ফ’নটোলৈ আৰু পোনপটীয়াকৈ চাওক"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"আপোনাৰ ফ’নটোলৈ আৰু পোনপটীয়াকৈ চাওক"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপোনাৰ মুখখন ঢাকি ৰখা বস্তুবোৰ আঁতৰাওক।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীনৰ ওপৰৰ অংশ চাফা কৰক"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"আপোনাৰ মুখাৱয়ব সম্পূৰ্ণৰূপে দেখা পোৱা হৈ থাকিবই লাগিব"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"আপোনাৰ মুখাৱয়ব সম্পূৰ্ণৰূপে দেখা পোৱা হৈ থাকিবই লাগিব"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"মুখাৱয়বৰ মডেল সৃষ্টি কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ডাঠ ৰঙৰ চশমা চিনাক্ত কৰা হৈছে। আপোনাৰ মুখাৱয়ব সম্পূৰ্ণৰূপে দেখা পোৱা হৈ থাকিবই লাগিব।"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"মুখাৱয়বত আৱৰণ চিনাক্ত কৰা হৈছে। আপোনাৰ মুখাৱয়ব সম্পূৰ্ণৰূপে দেখা পোৱা হৈ থাকিবই লাগিব।"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। হাৰ্ডৱেৰ নাই।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 862ef3cc93b7..a7911de524c5 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Barmaq izi ilə kiliddən çıxarma"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Barmaq izi sensorundan istifadə etmək mümkün deyil"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Təmir provayderini ziyarət edin."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Dəqiq üz datası əldə edilmədi. Yenidən cəhd edin."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Üz modelinizi yaratmaq olmur. Yenə cəhd edin."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Çox işıqlıdır. Daha az işıqlı şəkli sınayın."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Çox qaranlıqdır. Parlaq işıqdan istifadə edin."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Telefonu uzaq tutun."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Telefonu yaxına tutun."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Telefonu yuxarı tutun."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Telefonu aşağı tutun."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Telefonu sola hərəkət etdirin."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Telefonu sağa hərəkət etdirin."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Parlaq işıqdan istifadə edin"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaq tutun"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaxına tutun"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu yuxarı tutun"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Telefonu aşağı tutun"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Telefonu sola tutun"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Telefonu sağa tutun"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Birbaşa cihaza baxın."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Üzünüzü telefonun qarşısında sabit saxlayın."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Üzünüz görünmür. Telefonunuzu göz səviyyəsində saxlayın."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Cihaz stabil deyil. Telefonu tərpətməyin."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Üzünüzü yenidən qeydiyyatdan keçirin."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Digəri ilə oxşardır, pozanızı dəyişin."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı bir az döndərin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Başınızı azca əyin."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı bir az döndərin."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Üzü tanımaq olmur. Yenə cəhd edin."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Başınızın yerini bir az dəyişdirin"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonunuza düz baxın"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonunuza düz baxın"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Telefonunuza düz baxın"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Üzünüzü gizlədən maneələri kənarlaşdırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Qara panel daxil olmaqla, ekranın yuxarısını təmizləyin"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Üzünüz tam görünməlidir"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Üzünüz tam görünməlidir"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Üz modelinizi yaratmaq olmur. Yenə cəhd edin."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Tünd eynək aşkar edildi. Üzünüz tam görünməlidir."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Üz örtüyü aşkar edildi. Üzünüz tam görünməlidir."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Üz doğrulanmadı. Avadanlıq əlçatan deyil."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 4b51f2cc0630..0bc58320be0a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Otključavanje otiskom prsta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Ne možete da koristite senzor za otisak prsta"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posetite dobavljača za popravke."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Snimanje lica nije uspelo. Probajte ponovo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Pravljenje modela lica nije uspelo. Probajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše je svetlo. Probajte sa slabijim osvetljenjem."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Pretamno je. Probajte sa jačim osvetljenjem."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Udaljite telefon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Približite telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Pomerite telefon nagore."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Pomerite telefon nadole."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Pomerite telefon ulevo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Pomerite telefon udesno."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probajte sa jačim osvetljenjem"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomerite telefon nagore"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Pomerite telefon nadole"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Pomerite telefon ulevo"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Pomerite telefon udesno"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Gledajte pravo u uređaj."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Postavite lice direktno ispred telefona"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ne vidi se lice. Držite telefon u visini očiju."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Mnogo se pomerate. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrujte lice."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Više ne može da se prepozna lice. Probajte ponovo."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše je slično, promenite pozu."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje pomerite glavu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje pomerite glavu."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Lice nije prepoznato. Probajte ponovo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo pomerite glavu"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte pravo u telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte pravo u telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Gledajte pravo u telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zaklanja lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite gornji deo ekrana, uključujući crnu traku"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Lice mora da bude potpuno vidljivo"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Lice mora da bude potpuno vidljivo"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Pravljenje modela lica nije uspelo. Probajte ponovo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Otkrivene su tamne naočari. Lice mora da bude potpuno vidljivo."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Otkriveno je prekrivanje lica. Lice mora da bude potpuno vidljivo."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Provera lica nije uspela. Hardver nije dostupan."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3daea4b6896d..706c870575d5 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Разблакіраванне адбіткам пальца"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Не ўдалося скарыстаць сканер адбіткаў пальцаў"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Звярніцеся ў сэрвісны цэнтр."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Не атрымалася распазнаць твар. Паўтарыце спробу."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Не ўдалося стварыць мадэль твару. Паўтарыце."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадта светла. Прыглушыце асвятленне."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Занадта цёмна. Павялічце асвятленне."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Перамясціце тэлефон далей."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Перамясціце тэлефон бліжэй."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Перамясціце тэлефон вышэй."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Перамясціце тэлефон ніжэй."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Перамясціце тэлефон улева."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Перамясціце тэлефон управа."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Павялічце асвятленне"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Перамясціце тэлефон далей"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Перамясціце тэлефон бліжэй"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Перамясціце тэлефон вышэй"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Перамясціце тэлефон ніжэй"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Перамясціце тэлефон улева"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Перамясціце тэлефон управа"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Глядзіце прама на экран прылады."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Трымайце тэлефон прама перад тварам."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не відаць твару. Трымайце тэлефон на ўзроўні вачэй."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Трымайце прыладу нерухома. Трымайце тэлефон роўна."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Паўтарыце рэгістрацыю твару."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Не бачна розніцы. Памяняйце позу."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Вы занадта моцна павярнулі галаву."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Трымайце галаву прама."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Вы занадта моцна павярнулі галаву."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Твар не распазнаны. Паўтарыце спробу."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Крыху змяніце паставу галавы"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Глядзіце прама на экран тэлефона"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Глядзіце прама на экран тэлефона"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Глядзіце прама на экран тэлефона"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Прыміце ўсё, што закрывае ваш твар."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ачысціце ад бруду верхнюю частку экрана, у тым ліку чорную панэль"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Твар павінен быць цалкам бачным"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Твар павінен быць цалкам бачным"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Не ўдалося стварыць мадэль твару. Паўтарыце спробу."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Выяўлены цёмныя акуляры. Твар павінен быць цалкам бачным."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Нешта засланяе твар. Твар павінен быць цалкам бачным."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Твар не спраўджаны. Абсталяванне недаступнае."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a8de53abd886..6a8240a8b2f4 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Отключване с отпечатък"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Сензорът за отпечатъци не може да се използва"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетете оторизиран сервиз."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Лицето не бе заснето точно. Опитайте отново."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Моделът на лицето ви не бе създаден. Опитайте пак."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Твърде светло е. Опитайте при по-слабо осветление."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Твърде тъмно е. Опитайте при по-силно осветление."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Отдалечете телефона."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Доближете телефона."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Преместете телефона по-високо."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Преместете телефона по-ниско."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Преместете телефона наляво."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Преместете телефона надясно."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Опитайте при по-силно осветление"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Отдалечете телефона"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете телефона"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Преместете телефона по-високо"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Преместете телефона по-ниско"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Преместете телефона наляво"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Преместете телефона надясно"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Моля, гледайте точно към устройството си."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Позиционирайте лицето си директно пред телефона."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Лицето ви не се вижда. Дръжте телефона на нивото на очите си."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Твърде много движение. Дръжте телефона неподвижно."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Моля, регистрирайте лицето си отново."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Лицето не бе разпознато. Опитайте отново."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Позата ви е сходна с предишна. Моля, променете я."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не завъртайте главата си толкова много."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не накланяйте главата си толкова много."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не завъртайте главата си толкова много."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Лицето не е разпознато. Опитайте отново."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Леко променете позицията на главата си"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледайте директно към телефона си"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледайте директно към телефона си"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Гледайте директно към телефона си"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Премахнете всичко, което закрива лицето ви."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Почистете горната част на екрана си, включително черната лента"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Лицето ви трябва да е напълно видимо"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Лицето ви трябва да е напълно видимо"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Моделът на лицето ви не бе създаден. Опитайте отново."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Изглежда, че носите тъмни очила. То трябва да е напълно видимо."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Изглежда, че лицето ви е покрито. То трябва да е напълно видимо."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Лицето не може да се потвърди. Хардуерът не е налице."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c2a55f690d2c..2680ac10453c 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ফিঙ্গারপ্রিন্ট আনলক"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"আঙ্গুলের ছাপের সেন্সর ব্যবহার করা যাচ্ছে না"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"একজন মেরামতি মিস্ত্রির কাছে যান।"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"মুখের সঠিক ডেটা পাওয়া যায়নি। আবার চেষ্টা করুন।"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ফেস মডেল তৈরি করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"খুব উজ্জ্বল। আলো কমিয়ে চেষ্টা করে দেখুন।"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"খুব অন্ধকার। আরও উজ্জ্বল আলো ব্যবহার করে দেখুন।"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ফোনটি আরও দূরে নিয়ে যান।"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ফোনটি আরও কাছে নিয়ে আসুন।"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ফোন উঁচুতে তুলুন।"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ফোন নিচে নামান।"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ফোনটি বাঁদিকে সরান।"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ফোনটি ডানদিকে সরান।"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"আরও উজ্জ্বল আলো ব্যবহার করে দেখুন"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ফোন আরও দূরে নিয়ে যান"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ফোন আরও কাছে নিয়ে আসুন"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ফোন আরও উঁচুতে তুলুন"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ফোন নিচে নামান"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ফোন আপনার বাঁদিকে সরান"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ফোন আপনার ডানদিকে সরান"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"সরাসরি ডিভাইসের দিকে তাকান।"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"আপনার মুখ সরাসরি ফোনের সামনে রাখুন।"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"আপনার মুখ দেখা যাচ্ছে না। ফোন আপনার চোখের সোজাসুজি ধরুন।"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"খুব বেশি নড়ছে। ফোনটি যাতে না কাঁপে সেইভাবে ধরুন।"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"আপনার মুখের ছবি আবার নথিভুক্ত করুন।"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"একই ধরনের দেখতে, একটু অন্যদিকে ঘুরে দাঁড়ান।"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"আপনার মাথা একটু কম ঝোঁকান।"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপনার মাথাটি সামান্য ঘোরান।"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"মুখ শনাক্ত করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"আপনার মাথার পজিশন সামান্য পরিবর্তন করুন"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"আপনার ফোনের দিকে আরও সরাসরি তাকান"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"আপনার ফোনের দিকে আরও সরাসরি তাকান"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"আপনার ফোনের দিকে আরও সরাসরি তাকান"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপনার ফেসকে আড়াল করে এমন সব কিছু সরিয়ে দিন।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ব্ল্যাক বার সহ আপনার স্ক্রিনের উপরের অংশ মুছে ফেলুন"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"আপনার মুখ পুরোপুরি দৃশ্যমান হতে হবে"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"আপনার মুখ পুরোপুরি দৃশ্যমান হতে হবে"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ফেস মডেল তৈরি করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"কালো চশমা শনাক্ত করা হয়েছে। আপনার মুখ পুরোপুরি দৃশ্যমান হতে হবে।"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"মুখে মাস্ক শনাক্ত করা হয়েছে। আপনার মুখ পুরোপুরি দৃশ্যমান হতে হবে।"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ফেস যাচাই করা যায়নি। হার্ডওয়্যার উপলভ্য নেই।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 0f524b4fc89e..ce2ad150927a 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Otključavanje otiskom prsta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nije moguće koristiti senzor za otisak prsta"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite pružaoca usluga za popravke."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Lice nije snimljeno precizno. Pokušajte ponovo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nije moguće kreirati model lica. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše svijetlo. Probajte s blažim osvjetljenjem."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Previše je tamno. Pokušajte s jačim osvjetljenjem."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Odmaknite telefon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Primaknite telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Pomjerite telefon naviše."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Pomjerite telefon naniže."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Pomjerite telefon ulijevo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Pomjerite telefon udesno."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Odmaknite telefon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Primaknite telefon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomjerite telefon naviše"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Pomjerite telefon naniže"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Pomjerite telefon ulijevo"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Pomjerite telefon udesno"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Gledajte direktno u uređaj."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Postavite lice direktno ispred telefona"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ne vidi se lice. Držite telefon u visini očiju."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše pokreta. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte lice."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje zakrenite glavu."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Nije moguće prepoznati lice. Pokušajte ponovo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo promijenite položaj glave"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte direktno u telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte direktno u telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Gledajte direktno u telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite prepreke koje blokiraju vaše lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh ekrana, uključujući crnu traku"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Lice se mora u potpunosti vidjeti"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Lice se mora u potpunosti vidjeti"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nije moguće kreirati model lica. Pokušajte ponovo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Otkrivene su tamne naočale. Lice se mora u potpunosti vidjeti."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Otkriveno je pokrivalo preko lica. Lice se mora u potpunosti vidjeti."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nije moguće potvrditi lice. Hardver nije dostupan."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 501ca1d4430b..a751f8951d89 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueig amb empremta digital"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"No es pot utilitzar el sensor d\'empremtes digitals"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveïdor de reparacions."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"No es reconeix la teva cara. Torna-ho a provar."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"No es pot crear el model facial. Torna-ho a provar."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Massa brillant Prova una il·luminació més suau."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Massa fosc. Prova una il·luminació més brillant."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Allunya\'t del telèfon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Apropa el telèfon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mou el telèfon més amunt."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mou el telèfon més avall."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mou el telèfon cap a l\'esquerra."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mou el telèfon cap a la dreta."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova una il·luminació més brillant"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Allunya\'t del telèfon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Apropa el telèfon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mou el telèfon més amunt"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mou el telèfon més avall"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mou el telèfon cap a l\'esquerra"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mou el telèfon cap a la dreta"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira més directament cap al dispositiu."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Posa la cara directament davant del telèfon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se\'t veu la cara. Mantén el telèfon a l\'altura dels ulls."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Massa moviment. Subjecta bé el telèfon."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Torna a registrar la teva cara."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"És massa semblant; canvia de postura."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"No giris tant el cap."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"No inclinis tant el cap."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No giris tant el cap."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"No podem reconèixer la cara. Torna-ho a provar."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Canvia lleugerament la posició del cap"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira més directament al telèfon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira més directament al telèfon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Mira més directament al telèfon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"La cara ha de ser completament visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"La cara ha de ser completament visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"No es pot crear el model facial. Torna-ho a provar."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"S\'han detectat ulleres fosques. La cara ha de ser completament visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"S\'ha detectat una mascareta. La cara ha de ser completament visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No es pot verificar la cara. Maquinari no disponible."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f86e783f6b1d..5c23a054cffe 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Odemknutí otiskem prstu"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Snímač otisků prstů nelze použít"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštivte servis"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Obličej se nepodařilo zachytit. Zkuste to znovu."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Model se nepodařilo vytvořit. Zkuste to znovu."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Je příliš světlo. Zmírněte osvětlení."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Je moc velká tma. Přejděte na světlo."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Umístěte telefon dál."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Umístěte telefon blíž."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Umístěte telefon výš."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Umístěte telefon níž."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Přesuňte telefon vlevo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Přesuňte telefon vpravo."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Přejděte na světlo"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Umístěte telefon dál"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Umístěte telefon blíž"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Umístěte telefon výš"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Umístěte telefon níž"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Umístěte telefon víc doleva"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Umístěte telefon víc doprava"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Dívejte se přímo na zařízení."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Umístěte obličej přímo před telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Obličej není vidět. Držte telefon na úrovni očí."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Příliš mnoho pohybu. Držte telefon nehybně."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Zaznamenejte obličej znovu."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Příliš podobné, změňte výraz."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Natočte hlavu o něco méně."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nakloňte hlavu trochu méně."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Natočte hlavu o něco méně."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Obličej se nepodařilo rozpoznat. Zkuste to znovu."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Trochu změňte polohu hlavy"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Dívejte se přímo na telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Dívejte se přímo na telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Dívejte se přímo na telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstraňte vše, co vám zakrývá obličej."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistěte horní část obrazovky včetně černé části"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Obličej musí být plně viditelný"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Obličej musí být plně viditelný"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Model se nepodařilo vytvořit. Zkuste to znovu."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Byly zjištěny tmavé brýle. Obličej musí být plně viditelný."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Byl zjištěn zakrytý obličej. Obličej musí být plně viditelný."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Obličej nelze ověřit. Hardware není dostupný."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4fb375269b46..4db987f1b317 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Oplåsning med fingeraftryk"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Fingeraftrykslæseren kan ikke bruges"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Der blev ikke registreret ansigtsdata. Prøv igen."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Der er for lyst. Prøv en mere dæmpet belysning."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"For mørkt. Prøv med mere belysning."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Flyt telefonen længere væk."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Flyt telefonen tættere på."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Løft telefonen højere op."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Sænk telefonen."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Flyt telefonen til venstre."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Flyt telefonen til højre."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv med mere belysning"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Flyt telefonen længere væk"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Flyt telefonen tættere på"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Løft telefonen højere op"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Sænk telefonen"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Flyt telefonen længere til venstre for dig"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Flyt telefonen længere til højre for dig"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Kig mere direkte på din enhed."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Sørg for, at dit ansigt er direkte foran telefonen."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Dit ansigt kan ikke registreres. Hold din telefon i øjenhøjde."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Der er for meget bevægelse. Hold telefonen stille."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrer dit ansigt igen."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Det minder for meget om et andet. Skift stilling."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Du skal ikke dreje hovedet så meget."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Ret dit hoved lidt op."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Du skal ikke dreje hovedet så meget."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansigtet kan ikke genkendes. Prøv igen."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Flyt dit hoved en smule"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kig mere direkte på din telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kig mere direkte på din telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Kig mere direkte på din telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hvis noget skjuler dit ansigt, skal du fjerne det."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengør toppen af din skærm, inkl. den sorte bjælke"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Dit ansigt skal være helt synligt"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Dit ansigt skal være helt synligt"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Mørke briller er registreret. Dit ansigt skal være helt synligt."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Ansigtsdækning er registreret. Dit ansigt skal være helt synligt."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansigt ikke bekræftet. Hardware ikke tilgængelig."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index fae9dd7e617c..9344e52841d3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Entsperrung per Fingerabdruck"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Der Fingerabdrucksensor kann nicht verwendet werden"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Suche einen Reparaturdienstleister auf."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Gesichtsdaten nicht gut erfasst. Erneut versuchen."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kein Gesichtsmodell möglich. Versuche es erneut."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Zu hell. Schwächere Beleuchtung ausprobieren."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Zu dunkel. Probier eine hellere Beleuchtung aus."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Beweg das Telefon weiter weg."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Beweg das Telefon näher heran."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Halte das Smartphone höher."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Beweg das Smartphone nach unten."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Beweg das Smartphone nach links."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Beweg das Smartphone nach rechts."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probiere es mit einer helleren Beleuchtung"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Bewege das Smartphone weiter weg"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Bewege das Smartphone näher heran"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Bewege das Smartphone nach oben"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Bewege das Smartphone nach unten"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Bewege das Smartphone nach links"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Bewege das Smartphone nach rechts"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Bitte sieh direkt auf dein Gerät."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Halte dein Gesicht direkt vor dein Smartphone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Dein Gesicht wurde nicht erkannt. Halte dein Smartphone auf Augenhöhe."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Zu viel Unruhe. Halte das Smartphone ruhig."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Bitte registriere dein Gesicht noch einmal."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Zu ähnlich. Bitte dreh deinen Kopf etwas."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Dreh den Kopf etwas weniger zur Seite."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Neig den Kopf etwas weniger stark."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Neig den Kopf etwas weniger stark."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Gesicht nicht erkannt. Versuche es noch einmal."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ändere die Position deines Kopfes leicht"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Sieh direkt auf dein Smartphone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Sieh direkt auf dein Smartphone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Sieh direkt auf dein Smartphone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Entferne alles, was dein Gesicht verdeckt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinige den oberen Teil deines Bildschirms, einschließlich der schwarzen Leiste"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Dein Gesicht muss vollständig sichtbar sein"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Dein Gesicht muss vollständig sichtbar sein"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Dein Gesichtsmodell kann nicht erstellt werden. Versuche es noch einmal."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dunkle Brille erkannt. Dein Gesicht muss vollständig sichtbar sein."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Dein Gesicht ist bedeckt. Es muss vollständig sichtbar sein."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Gesicht nicht erkannt. Hardware nicht verfügbar."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 118b63b340dd..8389e3088878 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Ξεκλείδωμα με δακτυλικό αποτύπωμα"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Δεν είναι δυνατή η χρήση του αισθητήρα δακτυλικών αποτυπωμάτων"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Επισκεφτείτε έναν πάροχο υπηρεσιών επισκευής."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Αδύνατη λήψη ακριβών δεδομ. προσώπου. Επανάληψη."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Αδύν. η δημιουρ. του μοντ. προσώπ. Δοκιμάστε ξανά."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Υπερβολικά έντονος φωτισμός. Δοκιμάστε πιο ήπιο."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Πολύ σκοτεινό περιβάλλον. Φροντίστε τον φωτισμό."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Απομακρύνετε περισσότερο το τηλέφωνο."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Πλησιάστε περισσότερο το τηλέφωνο."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Μετακινήστε το τηλέφωνο πιο ψηλά."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Μετακινήστε το τηλέφωνο πιο χαμηλά."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Μετακινήστε το τηλέφωνο στα αριστερά."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Μετακινήστε το τηλέφωνο στα δεξιά."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Δοκιμάστε με περισσότερο φως"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Απομακρύνετε περισσότερο το τηλέφωνο"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Φέρτε πιο κοντά το τηλέφωνό σας"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Μετακινήστε το τηλέφωνο πιο ψηλά"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Μετακινήστε πιο χαμηλά το τηλέφωνο"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Μετακινήστε το τηλέφωνο προς τα αριστερά"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Μετακινήστε το τηλέφωνο προς τα δεξιά"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Κοιτάξτε απευθείας τη συσκευή σας."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Στρέψτε το πρόσωπό σάς απευθείας στο τηλέφωνο."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Δεν εντοπίστηκε το πρόσωπό σας. Κρατήστε το τηλέφωνο στο ύψος των ματιών."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Πάρα πολλή κίνηση. Κρατήστε σταθερό το τηλέφωνο."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Καταχωρίστε ξανά το πρόσωπό σας."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Πολύ παρόμοιο, αλλάξτε την πόζα σας."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Στρέψτε λιγότερο το κεφάλι σας."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Γείρετε λιγότερο το κεφάλι σας."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Στρέψτε λιγότερο το κεφάλι σας."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Το πρόσωπο δεν αναγνωρίζεται. Δοκιμάστε ξανά."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Αλλάξτε ελαφρώς τη θέση του κεφαλιού σας"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Κοιτάξτε απευθείας το τηλέφωνό σας"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Κοιτάξτε απευθείας το τηλέφωνό σας"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Κοιτάξτε απευθείας το τηλέφωνό σας"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Απομακρύνετε οτιδήποτε κρύβει το πρόσωπό σας."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Καθαρίστε το επάνω μέρος της οθόνης σας, συμπεριλαμβανομένης της μαύρης γραμμής"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Το πρόσωπό σας πρέπει να φαίνεται πλήρως."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Το πρόσωπό σας πρέπει να φαίνεται πλήρως."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Αδύνατη η δημιουργία του μοντέλου προσώπου. Δοκιμάστε ξανά."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Ανιχνεύτηκαν σκούρα γυαλιά. Το πρόσωπό σας πρέπει να φαίνεται πλήρως."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Ανιχνεύτηκε κάλυμμα προσώπου. Το πρόσωπό σας πρέπει να φαίνεται πλήρως."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Αδύν. επαλήθ. προσώπου. Μη διαθέσιμος εξοπλισμός."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 4e1c415db7a9..180ff8fa73db 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Can’t use fingerprint sensor"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Couldn’t capture accurate face data. Try again."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Too dark. Try brighter lighting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Move phone farther away."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Move phone closer."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Move phone higher."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Move phone lower."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Move phone to the left."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Move phone to the right."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Move phone lower"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Move phone to your left"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Move phone to your right"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Position your face directly in front of the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Look more directly at your phone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Your face must be fully visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Your face must be fully visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Can’t create your face model. Try again."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dark glasses detected. Your face must be fully visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Face covering detected. Your face must be fully visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 84f18810c9e8..aa94682722ca 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Can’t use fingerprint sensor"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Couldn’t capture accurate face data. Try again."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Too dark. Try brighter lighting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Move phone farther away."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Move phone closer."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Move phone higher."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Move phone lower."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Move phone to the left."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Move phone to the right."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Move phone lower"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Move phone to your left"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Move phone to your right"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Position your face directly in front of the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Look more directly at your phone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Your face must be fully visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Your face must be fully visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Can’t create your face model. Try again."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dark glasses detected. Your face must be fully visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Face covering detected. Your face must be fully visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 606dc80308e2..f4f7e80f6307 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Can’t use fingerprint sensor"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Couldn’t capture accurate face data. Try again."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Too dark. Try brighter lighting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Move phone farther away."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Move phone closer."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Move phone higher."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Move phone lower."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Move phone to the left."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Move phone to the right."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Move phone lower"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Move phone to your left"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Move phone to your right"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Position your face directly in front of the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Look more directly at your phone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Your face must be fully visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Your face must be fully visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Can’t create your face model. Try again."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dark glasses detected. Your face must be fully visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Face covering detected. Your face must be fully visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 399034380a9b..631cf2b0c3da 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Can’t use fingerprint sensor"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Couldn’t capture accurate face data. Try again."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Too dark. Try brighter lighting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Move phone farther away."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Move phone closer."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Move phone higher."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Move phone lower."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Move phone to the left."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Move phone to the right."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Move phone lower"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Move phone to your left"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Move phone to your right"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Position your face directly in front of the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Look more directly at your phone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Your face must be fully visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Your face must be fully visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Can’t create your face model. Try again."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dark glasses detected. Your face must be fully visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Face covering detected. Your face must be fully visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index b8aca7344ac3..3bb25cb3ebe4 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎Fingerprint Unlock‎‏‎‎‏‎"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‎Can’t use fingerprint sensor‎‏‎‎‏‎"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎Visit a repair provider.‎‏‎‎‏‎"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎Couldn’t capture accurate face data. Try again.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎Can’t create your face model. Try again.‎‏‎‎‏‎"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎Too bright. Try gentler lighting.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎Too dark. Try brighter lighting.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎Move phone farther away.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎Move phone closer.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎Move phone higher.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎Move phone lower.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‎Move phone to the left.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎Move phone to the right.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎Try brighter lighting‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎Move phone farther away‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎Move phone closer‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎Move phone higher‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎Move phone lower‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎Move phone to your left‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎Move phone to your right‎‏‎‎‏‎"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎Please look more directly at your device.‎‏‎‎‏‎"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎Position your face directly in front of the phone.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎Can’t see your face. Hold your phone at eye level.‎‏‎‎‏‎"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎Too much motion. Hold phone steady.‎‏‎‎‏‎"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎Please re-enroll your face.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎No longer able to recognize face. Try again.‎‏‎‎‏‎"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎Too similar, please change your pose.‎‏‎‎‏‎"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎Turn your head a little less.‎‏‎‎‏‎"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎Tilt your head a little less.‎‏‎‎‏‎"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎Turn your head a little less.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎Can’t recognize face. Try again.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎Change the position of your head slightly‎‏‎‎‏‎"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎Look more directly at your phone‎‏‎‎‏‎"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‎Look more directly at your phone‎‏‎‎‏‎"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎Look more directly at your phone‎‏‎‎‏‎"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎Remove anything hiding your face.‎‏‎‎‏‎"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎Clean the top of your screen, including the black bar‎‏‎‎‏‎"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎Your face must be fully visible‎‏‎‎‏‎"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎Your face must be fully visible‎‏‎‎‏‎"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎Can’t create your face model. Try again.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎Dark glasses detected. Your face must be fully visible.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎Face covering detected. Your face must be fully visible.‎‏‎‎‏‎"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎Can’t verify face. Hardware not available.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index cbdc457a232c..51b221924587 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueo con huellas dactilares"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"No se puede usar el sensor de huellas dactilares"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consulta a un proveedor de reparaciones."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Datos faciales imprecisos. Vuelve a intentarlo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear modelo de rostro. Reinténtalo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado brillante. Prueba con menos iluminación."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Demasiado oscuro. Prueba con más iluminación."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Aleja un poco más el teléfono."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Acerca el teléfono."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mueve el teléfono hacia arriba."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mueve el teléfono hacia abajo."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mueve el teléfono hacia la izquierda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mueve el teléfono hacia la derecha."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba con más iluminación"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono un poco más"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mueve el teléfono hacia arriba"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mueve el teléfono hacia abajo"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mueve el teléfono hacia la izquierda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mueve el teléfono hacia la derecha"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira directamente al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Ubica el rostro directamente frente al teléfono."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se ve tu cara. Sostén el teléfono a la altura de los ojos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te estás moviendo demasiado. No muevas el teléfono"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu rostro."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce el rostro. Vuelve a intentarlo."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Es muy similar a la anterior. Haz otra pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina un poco menos la cabeza."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira la cabeza un poco menos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"No se reconoce el rostro. Vuelve a intentarlo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia levemente la posición de la cabeza"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira el teléfono de forma más directa"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira el teléfono de forma más directa"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Mira el teléfono de forma más directa"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quítate cualquier objeto que te cubra el rostro."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra negra"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Tu rostro debe verse completamente"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Tu rostro debe verse completamente"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"No se puede crear modelo de rostro. Vuelve a intentarlo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Se detectaron lentes oscuros. Tu rostro debe verse completamente."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Se detectó que llevas mascarilla. Tu rostro debe verse completamente."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No se verificó el rostro. Hardware no disponible."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c44c9e9a7991..93058bcdbba8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueo con huella digital"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"No se puede usar el sensor de huellas digitales"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveedor de reparaciones."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Datos faciales no reconocidos. Vuelve a intentarlo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear tu modelo. Inténtalo de nuevo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Hay demasiada luz. Busca un sitio menos iluminado."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Demasiado oscuro. Prueba en un lugar con más luz."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Aleja el teléfono."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Acerca el teléfono."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Sube el teléfono."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Baja el teléfono."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mueve el teléfono hacia la izquierda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mueve el teléfono hacia la derecha."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba en un lugar con más luz"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Sube el teléfono"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Baja el teléfono"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mueve el teléfono hacia la izquierda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mueve el teléfono hacia la derecha"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira de forma más directa al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Coloca la cara directamente frente al teléfono."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se detecta tu cara. Sujeta el teléfono a la altura de los ojos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"El teléfono se mueve demasiado. Mantenlo quieto."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu cara."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Se parece mucha a la anterior. Pon otra cara."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"No inclines tanto la cabeza."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No gires tanto la cabeza."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"No se reconoce la cara. Inténtalo de nuevo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia ligeramente la posición de tu cabeza"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira al teléfono de forma más directa"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira al teléfono de forma más directa"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Mira al teléfono de forma más directa"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retira cualquier objeto que te tape la cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra de color negro"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Tu cara se debe poder ver por completo"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Tu cara se debe poder ver por completo"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"No se puede crear tu modelo. Inténtalo de nuevo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Gafas oscuras detectadas. Tu cara se debe poder ver por completo."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Mascarilla detectada. Tu cara se debe poder ver por completo."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No se puede verificar. Hardware no disponible."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index ec5e203234ab..85aab3337b0c 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Sõrmejäljega avamine"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Sõrmejäljeandurit ei saa kasutada"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Külastage remonditeenuse pakkujat."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Näoandmeid ei saanud jäädvustada. Proovige uuesti."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Teie näomudelit ei saa luua. Proovige uuesti."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Liiga ere. Proovige hämaramat valgust."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Liiga pime. Proovige parema valgustusega kohas."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Liigutage telefon kaugemale."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Liigutage telefon lähemale."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Liigutage telefoni kõrgemale."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Liigutage telefoni allapoole."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Liigutage telefoni vasakule."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Liigutage telefoni paremale."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proovige parema valgustusega kohas"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Liigutage telefoni kaugemale"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Liigutage telefoni lähemale"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Liigutage telefoni kõrgemale"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Liigutage telefoni allapoole"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Liigutage telefoni vasakule"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Liigutage telefoni paremale"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Vaadake otse oma seadmesse."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Hoidke oma nägu otse telefoni ees."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Teie nägu ei ole näha. Hoidke telefoni silmade kõrgusel."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Liiga palju liikumist. Hoidke telefoni paigal."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registreerige oma nägu uuesti."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Liiga sarnane, palun muutke oma asendit."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pöörake oma pead veidi vähem."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kallutage oma pead pisut vähem."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pöörake oma pead veidi vähem."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Nägu ei õnnestu tuvastada. Proovige uuesti."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Muutke pisut oma pea asendit"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Vaadake otse telefoni"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Vaadake otse telefoni"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Vaadake otse telefoni"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eemaldage kõik, mis varjab teie nägu."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhastage ekraani ülaosa, sh musta värvi riba"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Teie nägu peab olema täielikult nähtaval"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Teie nägu peab olema täielikult nähtaval"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Teie näomudelit ei saa luua. Proovige uuesti."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Tuvastati tumedad prillid. Teie nägu peab olema täielikult nähtaval."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Tuvastati nägu kattev ese. Teie nägu peab olema täielikult nähtaval."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nägu ei saa kinnitada. Riistvara pole saadaval."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 608368b5270e..9c08bcb2306f 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Hatz-marka bidez desblokeatzea"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Ezin da erabili hatz-marken sentsorea"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Jarri harremanetan konponketak egiten dituen hornitzaile batekin."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Ezin izan dira bildu argazkiaren datu zehatzak. Saiatu berriro."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ezin da sortu aurpegi-eredua. Saiatu berriro."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Argi gehiegi dago. Joan toki ilunago batera."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Ilunegi dago. Erabili argi gehiago."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Urrundu telefonoa."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Hurbildu telefonoa."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Igo telefonoa."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Jaitsi telefonoa."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mugitu telefonoa ezkerretara."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mugitu telefonoa eskuinetara."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Erabili argi gehiago"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Urrundu telefonoa"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Hurbildu telefonoa"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Igo telefonoa"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Jaitsi telefonoa"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Eraman telefonoa ezkerrera"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Eraman telefonoa eskuinera"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Begiratu zuzenago gailuari."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Ipini aurrez aurre aurpegia eta telefonoa."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ez da hauteman aurpegia. Eutsi telefonoari begien parean."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Mugimendu gehiegi dago. Eutsi tinko telefonoari."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Erregistratu berriro aurpegia."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Jarrera berdintsuegia da. Alda ezazu."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Biratu burua pixka bat gutxiago."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Makurtu burua pixka bat gutxiago."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Biratu burua pixka bat gutxiago."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Ez da hauteman aurpegia. Saiatu berriro."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Aldatu buruaren posizioa apur bat"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Begiratu zuzenago telefonoari"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Begiratu zuzenago telefonoari"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Begiratu zuzenago telefonoari"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Kendu aurpegia estaltzen dizuten gauzak."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Garbitu pantailaren goialdea, barra beltza barne"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Aurpegi osoak egon behar du ikusgai"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Aurpegi osoak egon behar du ikusgai"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Ezin da sortu aurpegi-eredua. Saiatu berriro."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Betaurreko ilunak hauteman dira. Aurpegi osoak egon behar du ikusgai."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Maskara bat hauteman da. Aurpegi osoak egon behar du ikusgai."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ezin da egiaztatu aurpegia. Hardwarea ez dago erabilgarri."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 8cf7e8ad6920..bde7a8fd6166 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"قفل‌گشایی با اثر انگشت"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"امکان استفاده از حسگر اثر انگشت وجود ندارد"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"به ارائه‌دهنده خدمات تعمیر مراجعه کنید."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"داده‌های دقیق چهره ضبط نشد. دوباره امتحان کنید."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"مدل چهره‌تان ایجاد نشد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"خیلی روشن است. روشنایی‌اش را ملایم‌تر کنید."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"خیلی تاریک است. تصویر را روشن‌تر کنید."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"تلفن را به دورتر منتقل کنید."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"تلفن را نزدیک‌تر بیاورید."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"تلفن را بالاتر ببرید."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"تلفن را پایین‌تر بیاورید."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"تلفن را به‌سمت چپ حرکت دهید."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"تلفن را به سمت راست حرکت دهید."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"نور را بیشتر کنید"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"تلفن را دورتر ببرید"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"تلفن را نزدیک‌تر بیاورید"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"تلفن را بالاتر ببرید"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"تلفن را پایین‌تر ببرید"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"تلفن را به‌سمت چپ ببرید"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"تلفن را به‌سمت راست ببرید"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"لطفاً مستقیم به دستگاه نگه کنید."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"صورتتان را مستقیماً روبروی تلفن قرار دهید."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"چهره‌تان دیده نمی‌شود. تلفن را هم‌سطح چشمانتان نگه دارید."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"حرکت خیلی زیاد است. تلفن را ثابت نگه‌دارید."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"لطفاً چهره‌تان را مجدداً ثبت کنید."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"سرتان را کمی کج بگیرید."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"چهره شناسایی نشد. دوباره امتحان کنید."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"موقعیت سرتان را کمی تغییر دهید"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"مستقیم‌تر به تلفن نگاه کنید"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"مستقیم‌تر به تلفن نگاه کنید"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"مستقیم‌تر به تلفن نگاه کنید"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهره‌تان است بردارید."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"چهره‌تان باید کاملاً نمایان باشد"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"چهره‌تان باید کاملاً نمایان باشد"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"مدل چهره‌تان ایجاد نشد. دوباره امتحان کنید."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"عینک تیره شناسایی شد. چهره‌تان باید کاملاً نمایان باشد."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"پوشش صورت شناسایی شد. چهره‌تان باید کاملاً نمایان باشد."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چهره تأیید نشد. سخت‌افزار در دسترس نیست."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 11524b20e655..6d2424f10a7c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Sormenjälkiavaus"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Sormenjälkitunnistinta ei voi käyttää"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ota yhteys korjauspalveluun."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Tarkan kasvodatan tallennus epäonnistui. Yritä uudelleen."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kasvomallia ei voi luoda. Yritä uudelleen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Liian kirkasta. Kokeile pehmeämpää valaistusta."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Liian pimeää. Kokeile kirkkaampaa valaistusta."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Siirrä puhelinta kauemmas."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Siirrä puhelinta lähemmäs."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Siirrä puhelinta ylemmäs."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Siirrä puhelinta alemmas."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Siirrä puhelinta vasemmalle."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Siirrä puhelinta oikealle."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Kokeile kirkkaampaa valaistusta"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Vie puhelin kauemmas"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Tuo puhelin lähemmäs"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Siirrä puhelinta ylemmäs"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Siirrä puhelinta alemmas"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Siirrä puhelinta vasemmalle"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Siirrä puhelinta oikealle"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Katso suoremmin laitteeseen."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Aseta kasvosi suoraan puhelimen eteen."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kasvoja ei näy. Pidä puhelinta silmien korkeudella."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Laite liikkui liikaa. Pidä puhelin vakaana."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Rekisteröi kasvot uudelleen."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Liian samanlainen, vaihda asentoa."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Käännä päätä vähän vähemmän."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kallista päätäsi vähän vähemmän."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Käännä päätä vähän vähemmän."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Kasvoja ei voi tunnistaa. Yritä uudelleen."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Liikuta päätä hieman"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Katso suoremmin puhelimeen"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Katso suoremmin puhelimeen"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Katso suoremmin puhelimeen"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Poista esteet kasvojesi edestä."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhdista näytön yläreuna, mukaan lukien musta palkki"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Kasvojen täytyy näkyä kokonaan"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Kasvojen täytyy näkyä kokonaan"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Kasvomallia ei voi luoda. Yritä uudelleen."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Tummat lasit havaittu. Kasvojen täytyy näkyä kokonaan."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Kasvot peittävä asia havaittu. Kasvojen täytyy näkyä kokonaan."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kasvoja ei voi vahvistaa. Laitteisto ei käytettäv."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index f52b9147d9cf..e709da86c71b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Déverrouillage par empreinte digitale"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Impossible d\'utiliser le capteur d\'empreintes digitales"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consultez un fournisseur de services de réparation."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Imposs. capt. données visage précises. Réessayez."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer votre modèle facial. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez un éclairage plus faible."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Trop sombre. Essayez avec un éclairage plus fort."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Déplacez le téléphone plus loin."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Rapprochez le téléphone."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Déplacez le téléphone plus haut."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Déplacez le téléphone plus bas."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Déplacez le téléphone vers la gauche."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Déplacez le téléphone vers la droite."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez avec un éclairage plus fort"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Tenez le téléphone plus haut"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Tenez le téléphone plus bas"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Déplacez le téléphone vers la gauche"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Déplacez le téléphone vers la droite"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Veuillez regarder plus directement votre appareil."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Placez votre visage directement devant le téléphone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Impossible de voir votre visage. Tenez votre téléphone à la hauteur des yeux."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Trop de mouvement. Tenez le téléphone immobile."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Veuillez inscrire votre visage à nouveau."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ce visage ne sera plus reconnu. Réessayez."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Trop similaire. Changez de pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins votre tête."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclinez un peu moins votre tête."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins votre tête."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Visage non reconnu. Réessayez."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Modifiez légèrement la position de votre tête"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Regardez plus directement votre téléphone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Regardez plus directement votre téléphone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Regardez plus directement votre téléphone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui pourrait couvrir votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez le haut de l\'écran, y compris la barre noire"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Votre visage doit être entièrement visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Votre visage doit être entièrement visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Impossible de créer votre modèle facial. Réessayez."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Lunettes sombres détectées. Votre visage doit être entièrement visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Couvre-visage détecté. Votre visage doit être entièrement visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. de vérif. visage. Matériel non accessible."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 06813e6c9ea3..a3abae1cd805 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Déverrouillage par empreinte digitale"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Impossible d\'utiliser le lecteur d\'empreinte digitale"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contactez un réparateur."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Capture du visage impossible. Réessayez."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer empreinte faciale. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez de baisser la lumière."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Trop sombre. Essayez une éclairage plus lumineux."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Éloignez le téléphone."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Rapprochez le téléphone."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Montez le téléphone."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Baissez le téléphone."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Déplacez le téléphone vers la gauche."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Déplacez le téléphone vers la droite."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez un éclairage plus lumineux"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Déplacez le téléphone vers le haut"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Déplacez le téléphone vers le bas"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Déplacez le téléphone vers la gauche"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Déplacez le téléphone vers la droite"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Veuillez regarder plus directement l\'appareil."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Placez votre visage en face du téléphone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Visage non détecté. Tenez votre téléphone à hauteur des yeux."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Trop de mouvement. Ne bougez pas le téléphone."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Veuillez enregistrer à nouveau votre visage."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Impossible de reconnaître le visage. Réessayez."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Ressemble à un visage existant, changez de pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins la tête."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Penchez un peu moins la tête."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins la tête."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Visage non reconnu. Réessayez."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Déplacez légèrement votre tête"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Regardez plus directement votre téléphone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Regardez plus directement votre téléphone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Regardez plus directement votre téléphone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui cache votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez la partie supérieure de l\'écran, y compris la barre noire"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Votre visage doit être entièrement visible"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Votre visage doit être entièrement visible"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Impossible de créer votre empreinte faciale. Réessayez."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Lunettes sombres détectées. Votre visage doit être entièrement visible."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Masque détecté. Votre visage doit être entièrement visible."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. valider visage. Matériel non disponible."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index c118efb9b3ea..9645208a15a7 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueo dactilar"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Non se puido usar o sensor de impresión dixital"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un provedor de reparacións."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Sen datos faciais exactos. Téntao de novo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Non se pode crear o modelo facial. Téntao de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Hai demasiada iluminación. Proba cunha máis suave."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Hai demasiada escuridade. Proba con máis luz."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Separa máis o teléfono."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Achega máis o teléfono."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Eleva o teléfono."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Baixa o teléfono."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Move o teléfono cara á esquerda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Move o teléfono cara á dereita."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proba con máis luz"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Afasta o teléfono"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Achega o teléfono"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Sube o teléfono"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Baixa o teléfono"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Move o teléfono cara á esquerda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Move o teléfono cara á dereita"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira o dispositivo de forma máis directa."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Coloca a cara directamente diante do teléfono."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Non se pode ver a túa cara. Coloca o teléfono á altura dos ollos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Demasiado movemento. Non movas o teléfono."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Volve rexistrar a túa cara."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"É moi similar. Cambia a pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Xira a cabeza un pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina a cabeza un pouco menos."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Xira a cabeza un pouco menos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Non se recoñeceu a cara. Téntao de novo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia lixeiramente a posición da cabeza"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira o teléfono de forma máis directa"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira o teléfono de forma máis directa"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Mira o teléfono de forma máis directa"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quita todo o que oculte a túa cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpa a parte superior da pantalla, incluída a barra de cor negra"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"A cara debe poder verse por completo"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"A cara debe poder verse por completo"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Non se pode crear o modelo facial. Téntao de novo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Detectáronse lentes escuras. A cara debe poder verse por completo."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Detectouse unha máscara. A cara debe poder verse por completo."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Sen verificar a cara. Hardware non dispoñible."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f850bfbd6d3d..889ef9cd6613 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ફિંગરપ્રિન્ટ અનલૉક"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ફિંગરપ્રિન્ટ સેન્સરનો ઉપયોગ કરી શકાતો નથી"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"રિપેર કરવાની સેવા આપતા પ્રદાતાની મુલાકાત લો."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ચહેરાનો સચોટ ડેટા કૅપ્ચર ન થયો. ફરી પ્રયાસ કરો."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"તમારા ચહેરાનું મૉડલ ન બનાવી શકાય. ફરી પ્રયાસ કરો."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"અતિશય પ્રકાશિત. થોડો હળવો પ્રકાશ અજમાવી જુઓ."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"અતિશય ઘેરી. વધુ ઝળહળતો પ્રકાશ અજમાવો"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ફોનને વધુ દૂર ખસેડો."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ફોનને વધુ નજીક લાવો."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ફોનને વધુ ઊંચે ખસેડો."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ફોનને થોડો નીચે ખસેડો."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ફોનને ડાબી બાજુ ખસેડો."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ફોનને જમણી બાજુ ખસેડો."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"વધુ પ્રકાશિત લાઇટિંગ અજમાવો"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ફોનને વધુ દૂર લઈ જાઓ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ફોનને વધુ નજીક લાવો"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ફોનને વધુ ઊંચે લઈ જાઓ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ફોનને થોડો નીચે લઈ જાઓ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ફોનને તમારી ડાબી બાજુએ લઈ જાઓ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ફોનને તમારી જમણી બાજુએ લઈ જાઓ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"કૃપા કરીને તમારા ડિવાઇસ તરફ સીધું જુઓ."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"તમારો ચહેરો તમારા ફોનની બિલકુલ સામે રાખો."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"તમારો ચહેરો દેખાતો નથી. તમારા ફોનને આંખના લેવલ પર પકડી રાખો."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ડિવાઇસ અસ્થિર છે. ફોનને સ્થિર રાખો."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"કૃપા કરીને તમારા ચહેરાની ફરી નોંધણી કરાવો."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ઘણી સમાનતા ધરાવે છે, કૃપા કરીને તમારો પોઝ બદલો."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"તમારું માથું થોડું ફેરવો."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"તમારું માથું થોડું ઓછું ટિલ્ટ કરો."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"તમારું માથું થોડું ઓછું ફેરવો."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ચહેરો ઓળખી શકતા નથી. ફરી પ્રયાસ કરો."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"તમારા માથાની સ્થિતિ સહેજ બદલો"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"વધારે પ્રમાણમાં સીધું તમારા ફોન તરફ જુઓ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"વધારે પ્રમાણમાં સીધું તમારા ફોન તરફ જુઓ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"વધારે પ્રમાણમાં સીધું તમારા ફોન તરફ જુઓ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"તમારા ચહેરાને છુપાવતી કંઈપણ વસ્તુ દૂર કરો."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"કાળી પટ્ટી સહિત, તમારી સ્ક્રીનની ટોચ સાફ કરો"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"તમારો આખો ચહેરો દેખાવો આવશ્યક છે"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"તમારો આખો ચહેરો દેખાવો આવશ્યક છે"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"તમારા ચહેરાનું મૉડલ ન બનાવી શકાય. ફરી પ્રયાસ કરો."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"કાળા ચશ્માંની ભાળ મળી. તમારો આખો ચહેરો દેખાવો આવશ્યક છે."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ચહેરો ઢંકાયેલો હોવાની ભાળ મળી. તમારો આખો ચહેરો દેખાવો આવશ્યક છે."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ચહેરો ચકાસી શકાતો નથી. હાર્ડવેર ઉપલબ્ધ નથી."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d8aaa51c4448..06fe4040d6b9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"फ़िंगरप्रिंट अनलॉक"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"फ़िंगरप्रिंट सेंसर इस्तेमाल नहीं किया जा सकता"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फ़िंगरप्रिंट सेंसर को रिपेयर करने की सेवा देने वाली कंपनी से संपर्क करें."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"चेहरे से जुड़ा सटीक डेटा कैप्चर नहीं किया जा सका. फिर से कोशिश करें."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"चेहरे का माॅडल नहीं बन सका. फिर से कोशिश करें."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"बहुत रोशनी है. हल्की रोशनी आज़माएं."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"बहुत अंधेरा है. बेहतर रोशनी में आज़माएं."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"फ़ोन को दूर ले जाएं."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"फ़ोन को नज़दीक ले जाएं."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"फ़ोन को और ऊपर ले जाएं."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"फ़ोन को थोड़ा नीचे ले जाएं."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"फ़ोन को बाईं ओर घुमाएं."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"फ़ोन को दाईं ओर घुमाएं."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"बेहतर रोशनी में कोशिश करें"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"फ़ोन को दूर ले जाएं"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"फ़ोन को नज़दीक लाएं"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"फ़ोन को थोड़ा और ऊपर ले जाएं"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"फ़ोन को थोड़ा नीचे ले जाएं"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"फ़ोन को अपनी बाईं ओर ले जाएं"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"फ़ोन को अपनी दाईं ओर ले जाएं"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"कृपया अपने डिवाइस की तरफ़ सीधे देखें."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"अपने चेहरे को फोन के ठीक सामने लाएं."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"आपका चेहरा नहीं दिख रहा है. फ़ोन को अपनी आंखों की सीध में पकड़कर रखें."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"डिवाइस बहुत ज़्यादा हिल रहा है. फ़ोन को बिना हिलाएं पकड़ें."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया फिर से अपने चेहरे की पहचान कराएं."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"चेहरा काफ़ी मिलता-जुलता है, कृपया अपना पोज़ बदलें."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"अपना सिर थोड़ा कम घुमाएं."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"अपने सिर को थोड़ा कम झुकाएं."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"अपना सिर थोड़ा कम घुमाएं."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"चेहरे की पहचान नहीं हुई. फिर से कोशिश करें."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"अपने सिर की पोज़िशन को थोड़ा बदलें"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"अपने फ़ोन की तरफ़ बिल्कुल सीधा देखें"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"अपने फ़ोन की तरफ़ बिल्कुल सीधा देखें"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"अपने फ़ोन की तरफ़ बिल्कुल सीधा देखें"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"आपके चेहरे को छिपाने वाली सभी चीज़ों को हटाएं."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"अपनी स्क्रीन के सबसे ऊपरी हिस्से को साफ़ करें, जिसमें काले रंग वाला बार भी शामिल है"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"आपका पूरा चेहरा दिखना चाहिए"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"आपका पूरा चेहरा दिखना चाहिए"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"चेहरे का माॅडल नहीं बन सका. फिर से कोशिश करें."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"आपने गहरे रंग का चश्मा पहना है. आपका पूरा चेहरा दिखना चाहिए."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"चेहरा ढका हुआ है. आपका पूरा चेहरा दिखना चाहिए."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"चेहरा नहीं पहचान पा रहे. हार्डवेयर उपलब्ध नहीं है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index b0bc0b73da1c..b7fbf2276e39 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Otključavanje otiskom prsta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Senzor otiska prsta ne može se koristiti"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite davatelja usluga popravaka."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Podaci o licu nisu točni. Pokušajte ponovo."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Izrada modela lica nije uspjela. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvijetlo je. Pokušajte sa slabijim svjetlom."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Pretamno je. Pokušajte s jačim osvjetljenjem."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Udaljite telefon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Približite telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Pomaknite telefon više."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Pomaknite telefon niže."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Pomaknite telefon ulijevo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Pomaknite telefon udesno."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomaknite telefon prema gore"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Pomaknite telefon prema dolje"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Pomaknite telefon ulijevo"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Pomaknite telefon udesno"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Gledajte izravnije prema uređaju."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Postavite lice izravno ispred telefona."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Vaše se lice ne vidi. Držite telefon u razini očiju."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše kretanja. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte svoje lice."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Lice nije prepoznato. Pokušajte ponovo."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite pozu."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nagnite glavu malo manje."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nagnite glavu malo manje."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Prepoznavanje lica nije uspjelo. Pokušajte ponovo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo pomaknite glavu"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte izravnije prema telefonu"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte izravnije prema telefonu"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Gledajte izravnije prema telefonu"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zakriva lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh zaslona, uključujući crnu traku"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Vaše lice mora biti potpuno vidljivo"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Vaše lice mora biti potpuno vidljivo"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Izrada modela lica nije uspjela. Pokušajte ponovo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Otkrivene su tamne naočale. Vaše lice mora biti potpuno vidljivo."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Otkriveno je prekrivanje lica. Vaše lice mora biti potpuno vidljivo."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Lice nije potvrđeno. Hardver nije dostupan."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8a0b1ff55db4..3cc4b63d70d4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Feloldás ujjlenyomattal"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nem lehet használni az ujjlenyomat-érzékelőt"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Keresse fel a szervizt."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Sikertelen az arc pontos rögzítése. Próbálja újra."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nem lehet létrehozni az arcmodellt. Próbálja újra."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Túl világos. Próbálja kevésbé erős világítással."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Túl sötét. Próbálja jobb megvilágítás mellett."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Tartsa távolabb a telefont."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Tartsa közelebb a telefont."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Emelje magasabbra a telefont."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Tartsa alacsonyabban a telefont."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mozgassa a telefont balra."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mozgassa a telefont jobbra."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Próbálja jobb megvilágítás mellett"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Tartsa távolabb a telefont"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Tartsa közelebb a telefont"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Emelje magasabbra a telefont"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Tartsa alacsonyabban a telefont"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mozgassa balra a telefont"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mozgassa jobbra a telefont"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Szemből nézzen az eszközre."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"A telefont közvetlenül az arca elé tegye."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nem látszik az arca. Tartsa szemmagasságban a telefonját."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Túl sok a mozgás. Tartsa stabilan a telefont."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Rögzítsen újra képet az arcáról."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Túlságosan hasonló, változtasson a pózon."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Kicsit kevésbé fordítsa el a fejét."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tartsa kicsit egyenesebben a fejét."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Kicsit kevésbé fordítsa el a fejét."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Az arc nem felismerhető. Próbálja újra."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Egy kicsit mozdítsa el a fejét"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Nézzen egyenesen a telefonjára"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Nézzen egyenesen a telefonjára"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Nézzen egyenesen a telefonjára"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Távolítson el mindent, ami takarja az arcát."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Tisztítsa meg a képernyő tetejét, a fekete sávot is beleértve."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Arcának teljesen láthatónak kell lennie"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Arcának teljesen láthatónak kell lennie"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nem lehet létrehozni az arcmodellt. Próbálja újra."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Sötét szemüveget észlelt a rendszer. Arcának teljesen láthatónak kell lennie."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Valami eltakarja az arcát. Arcának teljesen láthatónak kell lennie."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Sikertelen arcellenőrzés. A hardver nem érhető el."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 01d937586686..c9cf7a7560bb 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Մատնահետքով ապակողպում"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Մատնահետքերի սկաները հնարավոր չէ օգտագործել"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Այցելեք սպասարկման կենտրոն։"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Չհաջողվեց գրանցել դեմքի ճշգրիտ տվյալները։ Կրկնեք։"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Չհաջողվեց ստեղծել ձեր դեմքի մոդելը։ Նորից փորձեք։"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Շատ լուսավոր է։ Փորձեք ավելի թեթև լուսավորություն։"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Շատ մութ է։ Փորձեք ավելի պայծառ լուսավորություն։"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Փոքր-ինչ հեռու պահեք հեռախոսը։"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Մոտեցրեք հեռախոսը։"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Բարձրացրեք հեռախոսը։"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Իջեցրեք հեռախոսը։"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Տեղափոխեք հեռախոսը ձախ:"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Տեղափոխեք հեռախոսը աջ:"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Ավելի պայծառ դարձրեք լուսավորությունը"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Փոքր-ինչ հեռու պահեք հեռախոսը"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Մոտեցրեք հեռախոսը"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Բարձրացրեք հեռախոսը"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Իջեցրեք հեռախոսը"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Տեղափոխեք հեռախոսը ձախ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Տեղափոխեք հեռախոսը աջ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Նայեք ուղիղ էկրանին։"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Պահեք ձեր դեմքն անմիջապես հեռախոսի էկրանի դիմաց:"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ձեր դեմքը չի երևում։ Հեռախոսը պահեք աչքերի մակարդակում։"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Շատ եք շարժում։ Հեռախոսն անշարժ պահեք։"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Նորից փորձեք։"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Շատ նման է նախորդին։ Փոխեք ձեր դիրքը։"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Գլուխն ուղիղ պահեք։"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Գլուխը մի փոքր իջեցրեք։"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Գլուխն ուղիղ պահեք։"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Դեմքը չի հաջողվում ճանաչել։ Նորից փորձեք։"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Թեթևակի փոխեք գլխի դիրքը"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Նայեք ուղիղ էկրանին"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Նայեք ուղիղ էկրանին"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Նայեք ուղիղ էկրանին"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Հեռացրեք այն ամենը, ինչը թաքցնում է ձեր երեսը:"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Մաքրեք էկրանի վերևի մասը, ներառյալ սև գոտին"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Ձեր դեմքը պետք է ամբողջովին տեսանելի լինի"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Ձեր դեմքը պետք է ամբողջովին տեսանելի լինի"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Չհաջողվեց ստեղծել ձեր դեմքի մոդելը։ Նորից փորձեք։"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Հանեք ակնոցը։ Ձեր դեմքը պետք է ամբողջովին տեսանելի լինի։"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Դեմքի մի մասը ծածկված է։ Ձեր դեմքը պետք է ամբողջովին տեսանելի լինի։"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Չհաջողվեց հաստատել դեմքը։ Սարքն անհասանելի է:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 314f6e22380d..b4c864daf532 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Tidak dapat menggunakan sensor sidik jari"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Kunjungi penyedia reparasi."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Tidak bisa mengambil data wajah akurat. Coba lagi."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah Anda. Coba lagi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Coba cahaya yang lebih lembut."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Terlalu gelap. Coba pencahayaan yang lebih cerah."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Gerakkan ponsel menjauh."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Gerakkan ponsel mendekat."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Geser ponsel ke atas."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Geser ponsel ke bawah."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Gerakkan ponsel ke kiri."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Gerakkan ponsel ke kanan."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Coba pencahayaan yang lebih cerah"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan ponsel"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan ponsel"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Gerakkan ponsel ke atas"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Gerakkan ponsel ke bawah"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Gerakkan ponsel ke kiri Anda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Gerakkan ponsel ke kanan Anda"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Lihat langsung ke perangkat."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Posisikan wajah Anda tepat di depan ponsel."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Tidak dapat melihat wajah Anda. Pegang ponsel sejajar dengan mata."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Terlalu banyak gerakan. Stabilkan ponsel."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Daftarkan ulang wajah Anda."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu mirip, ubah pose Anda."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Putar sedikit kepala Anda."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Miringkan sedikit kepala Anda."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Putar sedikit kepala Anda."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Tidak dapat mengenali wajah. Coba lagi."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ubah sedikit posisi kepala"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Lihat lebih lurus ke arah ponsel"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Lihat lebih lurus ke arah ponsel"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Lihat lebih lurus ke arah ponsel"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Singkirkan apa saja yang menutupi wajah Anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bagian atas layar, termasuk kotak hitam"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Wajah Anda harus terlihat sepenuhnya"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Wajah Anda harus terlihat sepenuhnya"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Tidak dapat membuat model wajah Anda. Coba lagi."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Kacamata hitam terdeteksi. Wajah Anda harus terlihat sepenuhnya."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Penutup wajah terdeteksi. Wajah Anda harus terlihat sepenuhnya."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tidak dapat memverifikasi wajah. Hardware tidak tersedia."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 4346b6323de0..79ddc79a1219 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingrafarskenni"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Ekki er hægt að nota fingrafaralesara"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Þú verður að fara á verkstæði."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Nákvæm andlitsgögn fengust ekki. Reyndu aftur."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ekki tekst að búa til andlitslíkan. Reyndu aftur."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Of bjart. Prófaðu mýkri lýsingu."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Of dimmt. Prófaðu sterkari lýsingu."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Færðu símann lengra í burtu."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Færðu símann nær."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Færðu símann hærra."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Færðu símann neðar."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Færðu símann til vinstri."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Færðu símann til hægri."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prófaðu sterkari lýsingu"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Færðu símann lengra í burtu"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Færðu símann nær"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Færðu símann hærra"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Færðu símann neðar"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Færðu símann til vinstri"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Færðu símann til hægri"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Horfðu beint á tækið."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Hafðu andlitið beint fyrir framan símann."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Sé ekki andlitið á þér. Haltu símanum í augnhæð."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Of mikil hreyfing. Haltu símanum stöðugum."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Skráðu nafnið þitt aftur."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Of svipað. Stilltu þér öðruvísi upp."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Snúðu höfðinu aðeins minna."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Hallaðu höfðinu aðeins minna."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Snúðu höfðinu aðeins minna."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Andlit þekkist ekki. Reyndu aftur."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Breyttu stöðu höfuðsins örlítið"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Horfðu beint á símann"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Horfðu beint á símann"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Horfðu beint á símann"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjarlægðu það sem kann að hylja andlitið."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hreinsaðu efsta hluta skjásins þíns, þ.m.t. svörtu stikuna"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Allt andlitið á þér þarf að sjást"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Allt andlitið á þér þarf að sjást"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Ekki tekst að búa til andlitslíkan. Reyndu aftur."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Dökk gleraugu greindust. Allt andlitið á þér þarf að sjást."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Eitthvað er fyrir andlitinu. Allt andlitið á þér þarf að sjást."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Andlit ekki staðfest. Vélbúnaður er ekki tiltækur."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index bdc813c6cad9..9f5ca75010cb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Sblocco con l\'impronta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Impossibile utilizzare il sensore di impronte digitali"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contatta un fornitore di servizi di riparazione."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Impossibile acquisire dati viso accurati. Riprova."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossibile creare il modello del volto. Riprova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Troppa luce. Prova con una luce più soft."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Troppo buio. Prova con più luce."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Sposta il telefono più lontano."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Avvicina il telefono."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Sposta il telefono più in alto."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Sposta il telefono più in basso."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Sposta il telefono verso sinistra."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Sposta il telefono verso destra."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova con più luce"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Allontana il telefono"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Avvicina il telefono"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Sposta il telefono più in alto"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Sposta il telefono più in basso"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Sposta il telefono alla tua sinistra"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Sposta il telefono alla tua destra"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Guarda più direttamente verso il dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Posiziona il viso davanti al telefono."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Impossibile vedere il volto. Tieni il telefono all\'altezza degli occhi."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Troppo movimento. Tieni fermo il telefono."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ripeti l\'acquisizione del volto."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Non è più possibile riconoscere il volto. Riprova."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Troppo simile; cambia posa."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira un po\' meno la testa."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina un po\' meno la testa."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira un po\' meno la testa."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Impossibile riconoscere il volto. Riprova."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia leggermente la posizione della testa"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Guarda più direttamente verso il telefono"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Guarda più direttamente verso il telefono"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Guarda più direttamente verso il telefono"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Rimuovi tutto ciò che ti nasconde il viso."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pulisci la parte superiore dello schermo, inclusa la barra nera"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Il tuo volto deve essere visibile per intero"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Il tuo volto deve essere visibile per intero"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Impossibile creare il modello del volto. Riprova."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Sono stati rilevati occhiali scuri. Il tuo volto deve essere visibile per intero."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"È stata rilevata una mascherina. Il tuo volto deve essere visibile per intero."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. verificare volto. Hardware non disponibile."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5b43fe921666..b2e0802b7e09 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ביטול הנעילה בטביעת אצבע"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"לא ניתן להשתמש בחיישן טביעות האצבע"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"צריך ליצור קשר עם ספק תיקונים."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"לא ניתן היה לקלוט את הפנים במדויק. יש לנסות שוב."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"לא ניתן ליצור את התבנית לזיהוי הפנים. יש לנסות שוב."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"בהירה מדי. צריך תאורה עדינה יותר."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"התמונה חשוכה מדי. צריך תאורה חזקה יותר."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"יש להרחיק את הטלפון."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"צריך לקרב את הטלפון."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"צריך להרים את הטלפון גבוה יותר."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"צריך להוריד את הטלפון."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"צריך להזיז את הטלפון שמאלה."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"צריך להזיז את הטלפון ימינה."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"כדאי לנסות בתאורה חזקה יותר"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"צריך להרחיק את הטלפון"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"צריך לקרב את הטלפון"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"צריך להגביה את הטלפון"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"צריך להוריד את הטלפון"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"צריך להזיז את הטלפון שמאלה"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"צריך להזיז את הטלפון ימינה"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"יש להביט ישירות אל המכשיר."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"עליך למקם את הפנים ישירות מול הטלפון."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"אי אפשר לראות את הפנים שלך. צריך להחזיק את הטלפון בגובה העיניים."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"יותר מדי תנועה. יש להחזיק את הטלפון בצורה יציבה."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"יש לסרוק שוב את הפנים."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"דומה מדי, יש לשנות תנוחה."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"עליך ליישר קצת את הראש."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"יש ליישר קצת את הראש."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"צריך ליישר קצת את הראש."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"לא ניתן לזהות את הפנים. יש לנסות שוב."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"צריך לשנות מעט את תנוחת הראש"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"צריך להביט ישירות בטלפון"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"צריך להביט ישירות בטלפון"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"צריך להביט ישירות בטלפון"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"יש להסיר כל דבר שמסתיר את הפנים."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"צריך לנקות את החלק העליון של המסך, כולל הסרגל השחור"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"הפנים שלך חייבות להיות גלויות לגמרי"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"הפנים שלך חייבות להיות גלויות לגמרי"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"לא ניתן ליצור את התבנית לזיהוי הפנים. יש לנסות שוב."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"זוהו משקפיים כהים. הפנים שלך חייבות להיות גלויות לגמרי."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"זוהה כיסוי על הפנים. הפנים שלך חייבות להיות גלויות לגמרי."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"לא ניתן לאמת את הפנים. החומרה לא זמינה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9c9d9cfcab0f..fd66096708ce 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"指紋認証"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"指紋認証センサーを使用できません"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"修理業者に調整を依頼してください。"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"顔を認識できませんでした。もう一度お試しください。"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"顔モデルを作成できません。もう一度お試しください。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"明るすぎます。もっと暗い場所でお試しください。"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"暗すぎます。もっと明るい場所でお試しください。"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"スマートフォンをもっと離してください。"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"スマートフォンをもっと近づけてください。"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"スマートフォンを上に動かしてください。"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"スマートフォンを下に動かしてください。"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"スマートフォンを左に動かしてください。"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"スマートフォンを右に動かしてください。"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"もっと明るい場所でお試しください"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"スマートフォンをもっと離してください"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"スマートフォンをもっと近づけてください"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"スマートフォンをもっと上げてください"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"スマートフォンをもっと下げてください"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"スマートフォンを左に動かしてください"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"スマートフォンを右に動かしてください"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"もっとまっすぐデバイスに顔を向けてください。"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"顔をスマートフォンの真正面に向けてください。"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"顔を確認できません。スマートフォンを目の高さに合わせて持ってください。"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"あまり動かさないでください。安定させてください。"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"顔を登録し直してください。"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"顔を認識できなくなりました。もう一度お試しください。"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"似すぎています。ポーズを変えてください。"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"顔の向きを少し戻してください。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"顔を少し傾けてください。"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"顔の向きを少し戻してください。"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"顔を認識できません。もう一度お試しください。"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"顔の位置を少し変えてください"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"もっとまっすぐスマートフォンに顔を向けてください"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"もっとまっすぐスマートフォンに顔を向けてください"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"もっとまっすぐスマートフォンに顔を向けてください"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"顔を隠しているものをすべて外してください"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"黒いバーを含め、画面の上部をきれいにしてください"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"顔が完全に写るようにしてください"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"顔が完全に写るようにしてください"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"顔モデルを作成できません。もう一度お試しください。"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"サングラスが検出されました。顔が完全に写るようにしてください。"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"マスクが検出されました。顔が完全に写るようにしてください。"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"顔を確認できません。ハードウェアを利用できません。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 08ac1847157e..04681be5a1fe 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"თითის ანაბეჭდით განბლოკვა"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"თითის ანაბეჭდის სენსორის გამოყენება ვერ ხერხდება"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ეწვიეთ შეკეთების სერვისის პროვაიდერს."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"სახის ზუსტი მონაცემები არ აღიბეჭდა. ცადეთ ხელახლა."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"თქვენი სახის მოდელი ვერ იქმნება. ცადეთ ხელახლა."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"მეტისმეტად ნათელია. ცადეთ უფრო სუსტი განათება."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"მეტისმეტად ბნელია. ცადეთ უფრო ძლიერი განათება."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"გადაანაცვლეთ ტელეფონი უფრო შორს."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"მიიტანეთ ტელეფონი უფრო ახლოს."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"გადაანაცვლეთ ტელეფონი ზემოთ."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"გადაანაცვლეთ ტელეფონი ქვემოთ."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"გადაანაცვლეთ ტელეფონი მარცხნივ."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"გადაანაცვლეთ ტელეფონი მარჯვნივ."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ცადეთ უფრო ძლიერი განათება"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"გაწიეთ ტელეფონი უფრო შორს"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"მიიტანეთ ტელეფონი უფრო ახლოს"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"აწიეთ ტელეფონი ზემოთ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ჩაწიეთ ტელეფონი ქვემოთ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"გაწიეთ ტელეფონი თქვენგან მარცხნივ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"გაწიეთ ტელეფონი თქვენგან მარჯვნივ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"გთხოვთ, უფრო პირდაპირ შეხედოთ თქვენს მოწყობილობას."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"დაიჭირეთ სახე უშუალოდ ტელეფონის წინ."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"თქვენი სახე არ ჩანს. დაიჭირეთ ტელეფონი თვალის დონეზე."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"მეტისმეტად მოძრაობთ. მყარად დაიჭირეთ ტელეფონი."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"გთხოვთ, ხელახლა დაარეგისტრიროთ თქვენი სახე."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"მეტისმეტად მსგავსია. გთხოვთ, შეცვალოთ პოზა."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"თავი ცოტა ნაკლებად გადახარეთ."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"სახის ამოცნობა ვერ ხერხდება. ცადეთ ხელახლა."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ოდნავ შეცვალეთ თავის პოზიცია"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"პირდაპირ უყურეთ ტელეფონს"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"პირდაპირ უყურეთ ტელეფონს"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"პირდაპირ უყურეთ ტელეფონს"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"მოაშორეთ ყველაფერი, რაც სახეს გიფარავთ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"გაწმინდეთ ეკრანის ზედა ნაწილი, შავი ზოლის ჩათვლით."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"თქვენი სახე მთლიანად უნდა ჩანდეს"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"თქვენი სახე მთლიანად უნდა ჩანდეს"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"თქვენი სახის მოდელი ვერ იქმნება. ცადეთ ხელახლა."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"აღმოჩენილია მუქი სათვალე. თქვენი სახე მთლიანად უნდა ჩანდეს."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"აღმოჩენილია სახის დაფარვა. თქვენი სახე მთლიანად უნდა ჩანდეს."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"სახე ვერ დასტურდება. აპარატი მიუწვდომელია."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index a763f3f28d67..c966b958e4b8 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Құлыпты саусақ ізімен ашу"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Саусақ ізін оқу сканерін пайдалану мүмкін емес"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Жөндеу қызметіне барыңыз."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Бет деректері дұрыс алынбады. Әрекетті қайталаңыз."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Бет үлгісі жасалмады. Қайталап көріңіз."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Тым ашық. Күңгірттеу жарық керек."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Тым қараңғы. Молырақ жарық керек."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Телефонды алшақ ұстаңыз."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Телефонды жақынырақ ұстаңыз."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Телефонды жоғарырақ ұстаңыз."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Телефонды төменірек ұстаңыз."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Телефонды солға жылжытыңыз."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Телефонды оңға жылжытыңыз."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарық деңгейін арттырыңыз."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонды алшақ ұстаңыз."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонды жақынырақ ұстаңыз."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонды жоғарырақ ұстаңыз."</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Телефонды төменірек ұстаңыз."</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Телефонды солға қарай ұстаңыз."</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Телефонды оңға қарай ұстаңыз."</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Құрылғының камерасына тура қараңыз."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Бетіңізді телефонға тура қаратыңыз."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Бетіңіз көрінбей тұр. Телефонды көз деңгейінде ұстаңыз."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Қозғалыс тым көп. Телефонды қозғалтпаңыз."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Қайта тіркеліңіз."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Алдыңғысына тым ұқсас, басқаша қалыпта түсіңіз."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Басыңызды түзурек ұстаңыз."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Басыңызды түзуірек ұстаңыз."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Басыңызды кішкене бұрыңыз."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Бет танылмады. Қайталап көріңіз."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Басыңыздың қалпын сәл өзгертіңіз."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Телефонға барынша тура қараңыз."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Телефонға барынша тура қараңыз."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Телефонға барынша тура қараңыз."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Бетіңізді жауып тұрған нәрсені алып тастаңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экранның жоғарғы жағын, сонымен қатар қара жолақты өшіріңіз."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Бетіңіз толық көрініп тұруы керек."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Бетіңіз толық көрініп тұруы керек."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Бет үлгісі жасалмады. Қайталап көріңіз."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Қою түсті көзілдірік анықталды. Бетіңіз толық көрініп тұруы керек."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Бетперде анықталды. Бетіңіз толық көрініп тұруы керек."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Бетті тану мүмкін емес. Жабдық қолжетімді емес."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 6501755889f6..63f7b7c7d0c2 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ការដោះសោ​ដោយប្រើ​ស្នាមម្រាមដៃ"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"មិនអាចប្រើ​ឧបករណ៍ចាប់ស្នាមម្រាមដៃ​បានទេ"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ទាក់ទងក្រុមហ៊ុន​ផ្ដល់ការជួសជុល។"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"មិនអាច​ថត​ទិន្នន័យទម្រង់មុខ​បាន​ត្រឹមត្រូវទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"មិនអាចបង្កើតគំរូមុខរបស់អ្នកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ភ្លឺពេក។ សូមសាកល្បង​ប្រើ​ពន្លឺស្រាលជាងនេះ។"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ងងឹតជ្រុល។ សូមសាកល្បង​ប្រើ​ពន្លឺភ្លឺជាងនេះ។"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"រំកិល​ទូរសព្ទឱ្យឆ្ងាយ​ជាងមុន។"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ផ្លាស់ទី​ទូរសព្ទ​ឱ្យ​ជិត​ជាង​មុន។"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ផ្លាស់ទីទូរសព្ទឱ្យខ្ពស់ជាងមុន។"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ផ្លាស់ទីទូរសព្ទឱ្យទាបជាងមុន។"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ផ្លាស់ទី​ទូរសព្ទទៅខាងឆ្វេង។"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ផ្លាស់ទីទូរសព្ទទៅខាងស្ដាំ។"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"សាកល្បងប្រើ​ពន្លឺភ្លឺជាងនេះ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ដាក់​ទូរសព្ទឱ្យឆ្ងាយ​ជាងមុន"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ដាក់​ទូរសព្ទ​ឱ្យជិត​ជាងមុន"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ដាក់​ទូរសព្ទ​ឱ្យខ្ពស់​ជាងមុន"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ដាក់​ទូរសព្ទ​ឱ្យទាប​ជាងមុន"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ដាក់​ទូរសព្ទ​ទៅខាងឆ្វេងអ្នក"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ដាក់ទូរសព្ទ​ទៅខាងស្ដាំអ្នក"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"សូមមើល​ឱ្យចំ​ឧបករណ៍​របស់អ្នក​ជាងមុន។"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"បែរមុខ​របស់អ្នក​ឱ្យចំ​ពីមុខ​ទូរសព្ទ​ផ្ទាល់។"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"មើលមិនឃើញ​មុខរបស់អ្នកទេ។ កាន់ទូរសព្ទរបស់អ្នក​ដាក់ត្រឹមភ្នែក។"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"មាន​ចលនា​ខ្លាំងពេក។ សូមកាន់​ទូរសព្ទ​ឱ្យនឹង។"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"សូម​​ស្កេន​បញ្ចូល​មុខរបស់អ្នក​ម្ដងទៀត។"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"មិន​អាច​សម្គាល់មុខ​បាន​ទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ស្រដៀងគ្នា​ពេក សូមផ្លាស់ប្ដូរ​កាយវិការ​របស់អ្នក។"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ងាកក្បាល​របស់អ្នកតិចជាងមុន​បន្តិច។"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ផ្អៀងក្បាល​របស់អ្នក​តិចជាងនេះ​បន្តិច។"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ងាកក្បាល​របស់អ្នក​បន្តិចទៀត។"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"មិនអាចសម្គាល់មុខបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ប្ដូរទីតាំងក្បាល​របស់អ្នកតិចៗ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"មើល​ទូរសព្ទ​របស់អ្នក​ឱ្យចំជាងនេះ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"មើល​ទូរសព្ទ​របស់អ្នក​ឱ្យចំជាងនេះ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"មើល​ទូរសព្ទ​របស់អ្នក​ឱ្យចំជាងនេះ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"យកអ្វី​ដែលបាំង​មុខ​របស់អ្នកចេញ។"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"សម្អាតផ្នែកខាង​លើនៃ​អេក្រង់​របស់​អ្នក រួមទាំង​របារខ្មៅ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"មុខរបស់អ្នកត្រូវតែ​អាចមើលឃើញ​ពេញលេញ"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"មុខរបស់អ្នកត្រូវតែ​អាចមើលឃើញ​ពេញលេញ"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"មិនអាចបង្កើតគំរូមុខរបស់អ្នកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"បានរកឃើញ​វ៉ែនតាខ្មៅ។ មុខរបស់អ្នកត្រូវតែ​អាចមើលឃើញ​ពេញលេញ។"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"បានរកឃើញ​គ្រឿងពាក់លើមុខ។ មុខរបស់អ្នកត្រូវតែ​អាចមើលឃើញ​ពេញលេញ។"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"មិនអាច​ផ្ទៀងផ្ទាត់​មុខបានទេ។ មិនមាន​ហាតវែរទេ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 94caf85bc628..8d8d792ce008 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ರಿಪೇರಿ ಮಾಡುವವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ಸರಿಯಾಗಿ ಮುಖ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಲಾಗಲಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ಫೇಸ್ ಮಾಡೆಲ್ ರಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ ಮಂದ ಪ್ರಕಾಶಮಾನವಿರುವ ಲೈಟ್ ಬಳಸಿ"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ತುಂಬಾ ಕಪ್ಪು ಛಾಯೆಯಿದೆ. ಪ್ರಕಾಶಮಾನವಾದ ಲೈಟಿಂಗ್ ಬಳಸಿ."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ಫೋನ್ ಅನ್ನು ದೂರಕ್ಕೆ ಸರಿಸಿ."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ಫೋನ್ ಅನ್ನು ಸಮೀಪಕ್ಕೆ ತನ್ನಿ."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ಫೋನ್ ಅನ್ನು ಎತ್ತರಕ್ಕೆ ಹಿಡಿಯಿರಿ."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ಫೋನ್ ಅನ್ನು ಕೆಳಗೆ ಸರಿಸಿ."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ಫೋನ್ ಅನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ಫೋನ್ ಅನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ಪ್ರಕಾಶಮಾನವಾದ ಲೈಟಿಂಗ್ ಬಳಸಿ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ಫೋನ್ ಅನ್ನು ದೂರಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ಫೋನ್ ಅನ್ನು ಸಮೀಪಕ್ಕೆ ತನ್ನಿ"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ಫೋನ್ ಅನ್ನು ಎತ್ತರಕ್ಕೆ ಹಿಡಿಯಿರಿ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ಫೋನ್ ಅನ್ನು ಕೆಳಗೆ ಸರಿಸಿ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ಫೋನ್ ಅನ್ನು ನಿಮ್ಮ ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ಫೋನ್ ಅನ್ನು ನಿಮ್ಮ ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಹೆಚ್ಚಿನದ್ದನ್ನು ನೇರವಾಗಿ ನೋಡಿ."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ನಿಮ್ಮ ಮುಖವನ್ನು ಫೋನ್‌ಗೆ ನೇರವಾಗಿ ಇರಿಸಿ."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ನಿಮ್ಮ ಮುಖ ಕಾಣಿಸುತ್ತಿಲ್ಲ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಕಣ್ಣಿನ ನೇರಕ್ಕೆ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ತುಂಬಾ ಅಲುಗಾಡುತ್ತಿದೆ ಫೋನ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿ ಹಿಡಿಯಿರಿ."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ತುಂಬಾ ಸಮಾನ, ನಿಮ್ಮ ಪೋಸ್ ಬದಲಾಯಿಸಿ."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಓರೆಯಾಗಿಸಿ."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಕಡಿಮೆ ತಿರುಗಿಸಿ."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ನಿಮ್ಮ ತಲೆಯ ಸ್ಥಾನವನ್ನು ಸ್ವಲ್ಪ ಬದಲಾಯಿಸಿ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ನೋಡಿ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ನೋಡಿ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ನೋಡಿ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರೆಮಾಡುವ ಯಾವುದನ್ನಾದರೂ ತೆಗೆದುಹಾಕಿ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ಬ್ಲ್ಯಾಕ್ ಬಾರ್ ಸೇರಿದಂತೆ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲ್ಭಾಗವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ನಿಮ್ಮ ಮುಖವು ಸಂಪೂರ್ಣವಾಗಿ ಗೋಚರಿಸಬೇಕು"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ನಿಮ್ಮ ಮುಖವು ಸಂಪೂರ್ಣವಾಗಿ ಗೋಚರಿಸಬೇಕು"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ಫೇಸ್ ಮಾಡೆಲ್ ರಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ಕಪ್ಪು ಕನ್ನಡಕ ಪತ್ತೆಯಾಗಿದೆ. ನಿಮ್ಮ ಮುಖವು ಸಂಪೂರ್ಣವಾಗಿ ಗೋಚರಿಸಬೇಕು."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ಮುಖವಾಡ ಪತ್ತೆಯಾಗಿದೆ. ನಿಮ್ಮ ಮುಖವು ಸಂಪೂರ್ಣವಾಗಿ ಗೋಚರಿಸಬೇಕು."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ಮುಖ ದೃಢೀಕರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಹಾರ್ಡ್‌ವೇರ್ ಲಭ್ಯವಿಲ್ಲ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index eedcaf936a1a..0848dd60742b 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"지문 잠금 해제"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"지문 센서를 사용할 수 없음"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"수리업체에 방문하세요."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"정확한 얼굴 데이터를 캡처하지 못했습니다. 다시 시도하세요."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"얼굴 모델을 만들 수 없습니다. 다시 시도해 주세요."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"너무 밝습니다. 조명 밝기를 조금 낮춰보세요."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"너무 어둡습니다. 조명을 밝게 해 보세요."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"휴대전화를 더 멀리 위치시키세요."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"휴대전화를 더 가깝게 위치시키세요."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"휴대전화를 위쪽으로 이동하세요."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"휴대전화를 아래로 이동하세요"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"휴대전화를 왼쪽으로 이동하세요."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"휴대전화를 오른쪽으로 이동하세요."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"조명을 밝게 해 보세요."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"휴대전화를 얼굴에서 더 멀리 떨어뜨려 주세요."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"휴대전화를 얼굴에 더 가까이 가져와 주세요."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"휴대전화를 위로 이동하세요"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"휴대전화를 아래로 이동하세요"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"휴대전화를 왼쪽으로 이동하세요"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"휴대전화를 오른쪽으로 이동하세요"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"기기에서 더 똑바로 바라보세요."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"휴대전화가 얼굴 정면을 향하도록 두세요."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"얼굴이 보이지 않습니다. 눈높이에 맞춰 휴대전화를 들어 주세요."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"너무 많이 움직였습니다. 휴대전화를 흔들리지 않게 잡으세요."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"얼굴을 다시 등록해 주세요."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"너무 비슷합니다. 다른 포즈를 취해 보세요."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"고개를 조금 덜 돌려 보세요."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"고개를 조금 덜 기울여 보세요."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"고개를 조금 덜 돌려 보세요."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"얼굴을 인식할 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"얼굴의 위치를 조금 변경해 주세요."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"전체 얼굴이 보여야 합니다."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"전체 얼굴이 보여야 합니다."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"얼굴 모델을 만들 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"선글라스가 감지되었습니다. 전체 얼굴이 보여야 합니다."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"마스크가 감지되었습니다. 전체 얼굴이 보여야 합니다."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"얼굴을 확인할 수 없습니다. 하드웨어를 사용할 수 없습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 08fb1f00d509..05f3ebfd473f 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Кулпуланган түзмөктү манжа изи менен ачуу"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Манжа изинин сенсорун колдонууга болбойт"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Тейлөө кызматына кайрылыңыз."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Жүзүңүз жакшы тартылган жок. Кайталап көрүңүз."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Жүзүңүздүн үлгүсү түзүлгөн жок. Кайталаңыз."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Өтө жарык. Жарыктыкты азайтып көрүңүз."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Өтө караңгы. Жарыгыраак жерден тартып көрүңүз."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Телефонду алысыраак жылдырыңыз."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Телефонду жакыныраак жылдырыңыз."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Телефонду өйдө жылдырыңыз."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Телефонду ылдый жылдырыңыз."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Телефонду солго жылдырыңыз."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Телефонду оңго жылдырыңыз."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарыгыраак жерден тартып көрүңүз"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонду алысыраак жылдырыңыз"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонду жакыныраак жылдырыңыз"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонду жогору жылдырыңыз"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Телефонду ылдый жылдырыңыз"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Телефонду солго жылдырыңыз"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Телефонду оңго жылдырыңыз"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Түзмөгүңүзгө түз караңыз."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Телефонду жүзүңүздүн маңдайында кармаңыз."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Жүзүңүз көрүнбөй жатат. Телефонду көздөрүңүздүн деңгээлинде кармаңыз."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Кыймылдап жибердиңиз. Телефонду түз кармаңыз."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Жүзүңүздү кайра таанытыңыз."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Жүз таанылган жок. Кайталап көрүңүз."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Мурункуга окшош болуп калды, башкача туруңуз."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Башыңызды бир аз гана эңкейтиңиз."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Башыңызды бир аз гана эңкейтиңиз."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Башыңызды бир аз гана эңкейтиңиз."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Жүз таанылбай жатат. Кайталаңыз."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Башыңызды бир аз буруңуз"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Телефонуңузду караңыз"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Телефонуңузду караңыз"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Телефонуңузду караңыз"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Жүзүңүздү жашырып турган нерселерди алып салыңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экраныңыздын жогору жагын, анын ичинде тилкени да тазалаңыз"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Жүзүңүз толугу менен көрүнүшү керек"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Жүзүңүз толугу менен көрүнүшү керек"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Жүзүңүздүн үлгүсү түзүлгөн жок. Кайталаңыз."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Кара көз айнек аныкталды. Жүзүңүз толугу менен көрүнүшү керек."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Жүзүңүз жабылып турат. Жүзүңүз толугу менен көрүнүшү керек."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Жүз ырасталбай жатат. Аппараттык камсыздоо жеткиликсиз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index aa99ef19eb04..e4b34b19d1c2 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ປົດລັອກດ້ວຍລາຍນິ້ວມື"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ບໍ່ສາມາດໃຊ້ເຊັນ​ເຊີລາຍນິ້ວ​ມືໄດ້"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ກະລຸນາໄປຫາຜູ້ໃຫ້ບໍລິການສ້ອມແປງ."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ບໍ່ສາມາດບັນທຶກຂໍ້ມູນໃບໜ້າທີ່ຖືກຕ້ອງໄດ້. ກະລຸນາລອງໃໝ່."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ບໍ່ສາມາດສ້າງຮູບແບບໃບໜ້າຂອງທ່ານໄດ້. ກະລຸນາລອງໃໝ່."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ແຈ້ງເກີນໄປ. ລອງຄ່ອຍແສງໄຟລົງ."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ມືດເກີນ. ກະລຸນາລອງໃຊ້ສະພາບແສງທີ່ແຈ້ງຂຶ້ນ."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ຍ້າຍໂທລະສັບອອກໄປໄກຂຶ້ນ."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ຍ້າຍໂທລະສັບເຂົ້າໄປໃກ້ຂຶ້ນ."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ຍົກໂທລະສັບໃຫ້ສູງຂຶ້ນ."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ເລື່ອນໂທລະສັບຕ່ຳລົງ."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ຍ້າຍໂທລະສັບໄປທາງຊ້າຍ."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ຍ້າຍໂທລະສັບໄປທາງຂວາ."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ກະລຸນາລອງໃຊ້ສະພາບແສງທີ່ແຈ້ງຂຶ້ນ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ເລື່ອນໂທລະສັບອອກໄປໄກຂຶ້ນ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ເລື່ອນໂທລະສັບເຂົ້າໄປໃກ້ຂຶ້ນ"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ຍົກໂທລະສັບໃຫ້ສູງຂຶ້ນ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ເລື່ອນໂທລະສັບຕ່ຳລົງ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ເລື່ອນໂທລະສັບໄປທາງຊ້າຍຂອງທ່ານ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ເລື່ອນໂທລະສັບໄປທາງຂວາຂອງທ່ານ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"ກະລຸນາເບິ່ງອຸປະກອນຂອງທ່ານໃຫ້ຊື່ໆ."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ຫັນໜ້າຂອງທ່ານໄປໃສ່ໜ້າໂທລະສັບໂດຍກົງ."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ບໍ່ເຫັນໃບໜ້າຂອງທ່ານ. ຖືໂທລະສັບຂອງທ່ານໄວ້ໃນລະດັບສາຍຕາ."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ເຄື່ອນໄຫວຫຼາຍເກີນໄປ. ກະລຸນາຖືໂທລະສັບໄວ້ຊື່ໆ."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"ກະລຸນາລົງທະບຽນອຸປະກອນຂອງທ່ານອີກເທື່ອໜຶ່ງ."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ຄ້າຍກັນເກີນໄປ, ກະລຸນາປ່ຽນທ່າຂອງທ່ານ."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ປັບມຸມໜ້າຂອງທ່ານໃຫ້ຕັ້ງຊື່."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້. ກະລຸນາລອງໃໝ່."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ປ່ຽນຕຳແໜ່ງຂອງຫົວທ່ານເລັກນ້ອຍ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ເບິ່ງຊື່ໆໄປຫາໂທລະສັບຂອງທ່ານໃຫ້ຫຼາຍຂຶ້ນ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ເບິ່ງຊື່ໆໄປຫາໂທລະສັບຂອງທ່ານໃຫ້ຫຼາຍຂຶ້ນ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ເບິ່ງຊື່ໆໄປຫາໂທລະສັບຂອງທ່ານໃຫ້ຫຼາຍຂຶ້ນ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ນຳສິ່ງທີ່ກີດຂວາງໃບໜ້າທ່ານອອກ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ທຳຄວາມສະອາດສ່ວນເທິງສຸດຂອງໜ້າຈໍທ່ານ, ຮວມທັງແຖບດຳນຳ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ໃບໜ້າຂອງທ່ານຕ້ອງສະແດງໃຫ້ເຫັນໝົດ"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ໃບໜ້າຂອງທ່ານຕ້ອງສະແດງໃຫ້ເຫັນໝົດ"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ບໍ່ສາມາດສ້າງຮູບແບບໃບໜ້າຂອງທ່ານໄດ້. ກະລຸນາລອງໃໝ່."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ກວດພົບແວ່ນຕາດຳ. ໃບໜ້າຂອງທ່ານຕ້ອງສະແດງໃຫ້ເຫັນໝົດ."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ກວດພົບການປົກປິດໃບໜ້າ. ໃບໜ້າຂອງທ່ານຕ້ອງສະແດງໃຫ້ເຫັນໝົດ."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ບໍ່ສາມາດຢັ້ງຢືນໃບໜ້າໄດ້. ບໍ່ມີຮາດແວໃຫ້ໃຊ້."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b368facd99c..dfa4b57d2405 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Atrakinimas kontroliniu kodu"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Negalima naudoti kontrolinio kodo jutiklio"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Apsilankykite pas taisymo paslaugos teikėją."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Neužfiks. tikslūs veido duom. Bandykite dar kartą."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nepavyko sukurti veido modelio. Band. dar kartą."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Per šviesu. Išbandykite mažesnį apšvietimą."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Per tamsu. Išbandykite šviesesnį apšvietimą."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Laikykite telefoną toliau."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Laikykite telefoną arčiau."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Laikykite telefoną aukščiau."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Laikykite telefoną žemiau."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Pasukite telefoną kairėn."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Pasukite telefoną dešinėn."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Išbandykite šviesesnį apšvietimą"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Laikykite telefoną toliau"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Laikykite telefoną arčiau"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Laikykite telefoną aukščiau"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Laikykite telefoną žemiau"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Laikykite telefoną kairiau"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Laikykite telefoną dešiniau"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Žiūrėkite tiesiai į įrenginį."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Veidas turi būti prieš telefoną."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nepavyko pamatyti jūsų veido. Laikykite telefoną akių lygyje."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Įrenginys per daug judinamas. Nejudink. telefono."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Užregistruokite veidą iš naujo."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Per daug panašu, pakeiskite veido išraišką."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nesukite tiek galvos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Pakreipkite galvą šiek tiek mažiau."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nesukite tiek galvos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Veidas neatpažintas. Bandykite dar kartą."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Kaskart šiek tiek pakeiskite galvos poziciją"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Žiūrėkite tiesiai į telefoną"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Žiūrėkite tiesiai į telefoną"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Žiūrėkite tiesiai į telefoną"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Patraukite viską, kas užstoja jūsų veidą."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Išvalykite ekrano viršų, įskaitant juodą juostą"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Veidas turi būti visas matomas"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Veidas turi būti visas matomas"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nepavyko sukurti veido modelio. Band. dar kartą."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Aptikti akiniai nuo saulės. Visas veidas turi būti matomas."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Aptikta veido kaukė. Visas veidas turi būti matomas."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nepavyko patv. veido. Aparatinė įranga negalima."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 4d57390d3baa..d965fea166ea 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Autorizācija ar pirksta nospiedumu"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nevar izmantot pirksta nospieduma sensoru"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Sazinieties ar remonta pakalpojumu sniedzēju."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Neizdevās tvert sejas datus. Mēģiniet vēlreiz."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nevar izveidot sejas modeli. Mēģiniet vēlreiz."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Pārāk spilgts. Izmēģiniet maigāku apgaismojumu."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Pārāk tumšs. Izmēģiniet spožāku apgaismojumu."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Pārvietojiet tālruni tālāk."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Pārvietojiet tālruni tuvāk."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Paceliet tālruni augstāk."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Nolaidiet tālruni zemāk"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Pārvietojiet tālruni pa kreisi."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Pārvietojiet tālruni pa labi."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Izmēģiniet spožāku apgaismojumu."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Pārvietojiet tālruni tālāk."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Pārvietojiet tālruni tuvāk."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Paceliet tālruni augstāk."</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Nolaidiet tālruni zemāk."</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Pārvietojiet tālruni pa kreisi."</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Pārvietojiet tālruni pa labi."</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Lūdzu, tiešāk skatieties uz savu ierīci."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Novietojiet savu seju tieši pretī tālrunim."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Seja nav redzama. Turiet tālruni acu līmenī."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Pārāk daudz kustību. Nekustīgi turiet tālruni."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Lūdzu, atkārtoti reģistrējiet savu seju."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Pārāk līdzīgi. Lūdzu, mainiet pozu."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pagrieziet galvu nedaudz mazāk."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nedaudz mazāk nolieciet galvu."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pagrieziet galvu nedaudz mazāk."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Nevar atpazīt seju. Mēģiniet vēlreiz."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nedaudz mainiet galvas pozīciju."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Skatieties tieši uz tālruni."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Skatieties tieši uz tālruni."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Skatieties tieši uz tālruni."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Noņemiet visu, kas aizsedz jūsu seju."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Notīriet ekrāna augšdaļu, tostarp melno joslu."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Sejai ir jābūt pilnībā redzamai."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Sejai ir jābūt pilnībā redzamai."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nevar izveidot sejas modeli. Mēģiniet vēlreiz."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Konstatētas tumšas brilles. Sejai ir jābūt pilnībā redzamai."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Konstatēts sejas aizsegs. Sejai ir jābūt pilnībā redzamai."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nevar verificēt seju. Aparatūra nav pieejama."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 2c346fde719e..e182833c6886 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Отклучување со отпечаток на прст"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Не може да се користи сензорот за отпечатоци"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Однесете го на поправка."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Не се сними прецизна слика. Обидете се повторно."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Не може да создаде модел на лик. Обидете се пак."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Премногу светла. Пробајте со послабо осветлување."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Премногу темна. Пробајте со посилно осветлување."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Оддалечете го телефонот."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Доближете го телефонот."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Поткренете го телефонот."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Снижете го телефонот."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Поместете го телефонот налево."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Поместете го телефонот надесно."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте со посилно осветлување"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Оддалечете го телефонот"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете го телефонот"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Кренете го телефонот погоре"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Спуштете го телефонот подолу"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Поместете го телефонот налево"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Поместете го телефонот надесно"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Погледнете подиректно во уредот."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Наместете го лицето директно пред телефонот."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не ви се гледа лицето. Држете го телефонот во висина на очите."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Премногу движење. Држете го телефонот стабилно."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторно регистрирајте го лицето."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ликот не се препознава. Обидете се повторно."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Премногу слично, сменете ја позата."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не вртете ја главата толку многу."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не навалувајте ја главата толку многу."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не вртете ја главата толку многу."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Не се препознава ликот. Обидете се пак."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Малку сменете ја положбата на главата"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледајте подиректно во телефонот"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледајте подиректно во телефонот"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Гледајте подиректно во телефонот"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Отстранете ги работите што ви го покриваат лицето."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Исчистете го врвот на екранот, вклучувајќи ја црната лента"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Лицето мора да ви се гледа целосно"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Лицето мора да ви се гледа целосно"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Не може да создаде модел на лик. Обидете се пак."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Носите темни очила. Лицето мора да ви се гледа целосно."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Лицето е покриено. Лицето мора да ви се гледа целосно."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ликот не може да се потврди. Хардвер - недостапен."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 539a00a61bc2..c735ff5361d1 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ഫിംഗർപ്രിന്റ് അൺലോക്ക്"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"വിരലടയാള സെൻസർ ഉപയോഗിക്കാനാകുന്നില്ല"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"റിപ്പയർ കേന്ദ്രം സന്ദർശിക്കുക."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"കൃത്യ മുഖ ഡാറ്റ എടുക്കാനായില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"മുഖ മോഡൽ സൃഷ്ടിക്കാനാകില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"വളരെയധികം തെളിച്ചം. സൗമ്യതയേറിയ പ്രകാശം ശ്രമിക്കൂ."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"വളരെ ഇരുണ്ടത്. തിളക്കമേറിയ ലൈറ്റിംഗ് പരീക്ഷിക്കുക."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ഫോൺ കൂടുതൽ അകലേയ്ക്ക് നീക്കുക."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ഫോൺ അടുത്തേക്ക് നീക്കുക."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ഫോൺ മുകളിലേക്ക് ഉയർത്തുക"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ഫോൺ കൂടുതൽ താഴേക്ക് നീക്കുക."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ഫോൺ ഇടത്തോട്ട് നീക്കുക."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ഫോൺ വലത്തോട്ട് നീക്കുക."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"തിളക്കമേറിയ ലൈറ്റിംഗ് പരീക്ഷിച്ച് നോക്കൂ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ഫോൺ കൂടുതൽ ദൂരേയ്ക്ക് നീക്കുക"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ഫോൺ അടുത്തേക്ക് നീക്കുക"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ഫോൺ മുകളിലേക്ക് ഉയർത്തുക"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ഫോൺ കൂടുതൽ താഴേക്ക് നീക്കുക"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ഫോൺ നിങ്ങളുടെ ഇടതുവശത്തേക്ക് നീക്കുക"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ഫോൺ നിങ്ങളുടെ വലതുവശത്തേക്ക് നീക്കുക"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"നിങ്ങളുടെ ഉപകരണത്തിന് നേരെ കൂടുതൽ നന്നായി നോക്കുക."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"നിങ്ങളുടെ മുഖം ക്യാമറയ്‌ക്ക് നേരെയാക്കുക."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"നിങ്ങളുടെ മുഖം കാണാനാകുന്നില്ല. നിങ്ങളുടെ ഫോൺ കണ്ണിന് നേരെ പിടിക്കുക."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"വളരെയധികം ചലനം. ഫോൺ അനക്കാതെ നേരെ പിടിക്കുക."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യുക."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"വളരെയധികം സമാനത, നിങ്ങളുടെ പോസ് മാറ്റുക."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"നിങ്ങളുടെ തല ചെറുതായി ടിൽറ്റ് ചെയ്യുക."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"നിങ്ങളുടെ തലയുടെ സ്ഥാനം ചെറുതായി മാറ്റുക"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"കൂടുതൽ കൃത്യമായി ഫോണിന് നേരെ നോക്കുക"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"കൂടുതൽ കൃത്യമായി ഫോണിന് നേരെ നോക്കുക"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"കൂടുതൽ കൃത്യമായി ഫോണിന് നേരെ നോക്കുക"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"നിങ്ങളുടെ മുഖം മറയ്‌ക്കുന്നത് എല്ലാം നീക്കം ചെയ്യൂ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"കറുപ്പ് ബാർ ഉൾപ്പെടെ നിങ്ങളുടെ സ്ക്രീനിന്റെ മുകൾഭാഗം വൃത്തിയാക്കുക"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"നിങ്ങളുടെ മുഖം പൂർണ്ണമായും ദൃശ്യമായിരിക്കണം"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"നിങ്ങളുടെ മുഖം പൂർണ്ണമായും ദൃശ്യമായിരിക്കണം"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"മുഖ മോഡൽ സൃഷ്ടിക്കാനാകില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"കറുത്ത കണ്ണട കണ്ടെത്തി. നിങ്ങളുടെ മുഖം പൂർണ്ണമായും ദൃശ്യമായിരിക്കണം."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"മുഖം മറച്ചിരിക്കുന്നതായി കണ്ടെത്തി. നിങ്ങളുടെ മുഖം പൂർണ്ണമായും ദൃശ്യമായിരിക്കണം."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. ഹാർഡ്‌വെയർ ലഭ്യമല്ല."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 38056dddfa19..8265c910e5f6 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Хурууны хээгээр түгжээ тайлах"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Хурууны хээ мэдрэгч ашиглах боломжгүй"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Засварын үйлчилгээ үзүүлэгчид зочилно уу."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Царайн өгөгдлийг зөв авч чадсангүй. Дахин оролдоно уу."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Нүүрний загвар үүсгэж чадсангүй. Дахин оролдоно уу."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Хэт цайвар байна. Гэрэл багатай газар оролдоно уу."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Хэт харанхуй байна. Гэрэлтэй орчинд туршина уу."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Утсаа холдуулна уу."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Утсаа ойртуулна уу."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Утсаа дээшлүүлнэ үү."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Утсаа доошлуулна уу."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Утсаа зүүн тийш болгоно уу."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Утсаа баруун тийш болгоно уу."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Гэрэлтэй орчинд туршина уу"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Утсаа холдуулна уу"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Утсаа ойртуулна уу"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Утсаа дээшлүүлнэ үү"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Утсаа доошлуулна уу"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Утсаа зүүн тийш болгоно уу"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Утсаа баруун тийш болгоно уу"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Төхөөрөмж рүүгээ аль болох эгц харна уу."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Царайгаа утасны урд эгц байрлуулна уу"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Таны нүүрийг харагдахгүй байна. Утсаа нүднийхээ түвшинд барина уу."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Хэт их хөдөлгөөнтэй байна. Утсаа хөдөлгөөнгүй барина уу."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Нүүрээ дахин бүртгүүлнэ үү."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Хэт адилхан байгаа тул байрлалаа өөрчилнө үү."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Толгойгоо арай багаар эргүүлнэ үү."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Толгойгоо арай бага хазайлгана уу."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Толгойгоо арай багаар эргүүлнэ үү."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Царайг танихгүй байна. Дахин оролдоно уу."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Толгойныхоо байрлалыг бага зэрэг өөрчилнө үү"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Утас руугаа аль болох эгц харна уу"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Утас руугаа аль болох эгц харна уу"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Утас руугаа аль болох эгц харна уу"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Таны нүүрийг далдалж буй аливаа зүйлийг хасна уу."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Хар хэсэг зэрэг дэлгэцийнхээ дээд хэсгийг цэвэрлэнэ үү"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Таны нүүр бүтэн харагдах ёстой"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Таны нүүр бүтэн харагдах ёстой"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Нүүрний загвар үүсгэж чадсангүй. Дахин оролдоно уу."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Хар шил илэрлээ. Таны нүүр бүтэн харагдах ёстой."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Нүүрний халхавч илэрлээ. Таны нүүр бүтэн харагдах ёстой."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Царайг бататгаж чадсангүй. Техник хангамж боломжгүй байна."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1e2b43b81827..b04d7617fef4 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"फिंगरप्रिंट अनलॉक"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"फिंगरप्रिंट सेन्सर वापरू शकत नाही"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"दुरुस्तीच्या सेवा पुरवठादाराला भेट द्या."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"अचूक फेस डेटा कॅप्चर करता आला नाही. पुन्हा करा."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"फेस मॉडेल तयार करू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"खूप प्रखर. आणखी सौम्य प्रकाश वापरून पहा."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"खूप गडद. आणखी प्रखर प्रकाश वापरून पहा."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"फोन आणखी दूर हलवा"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"फोन आणखी जवळ हलवा."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"फोन आणखी वर हलवा."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"फोन आणखी खाली हलवा."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"फोन डावीकडे हलवा."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"फोन उजवीकडे हलवा."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"आणखी प्रखर प्रकाश वापरून पहा"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"फोन आणखी दूर हलवा"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"फोन आणखी जवळ हलवा"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"फोन आणखी वर हलवा"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"फोन आणखी खाली हलवा"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"फोन तुमच्या डावीकडे हलवा"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"फोन तुमच्या उजवीकडे हलवा"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"कृपया तुमच्या डिव्हाइसकडे थेट पहा"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"तुमचा चेहरा थेट फोन समोर आणा."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"तुमचा चेहरा दिसत नाही. तुमचा फोन डोळ्याच्या पातळीवर धरा."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"खूप हलत आहे. फोन स्थिर धरून ठेवा."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"एकाच प्रकारची पोझ देत आहात कृपया तुमची पोझ बदला."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"तुमचे डोके थोडे कमी फिरवा."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"तुमचे डोके थोडे कमी तिरपे करा."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"तुमचे डोके थोडे कमी फिरवा."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"तुमच्या डोक्याचे स्थान किंचित बदला"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"तुमच्या फोनकडे आणखी थेट पहा"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"तुमच्या फोनकडे आणखी थेट पहा"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"तुमच्या फोनकडे आणखी थेट पहा"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तुमचा चहेरा लपवणारे काहीही काढून टाका."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ब्लॅक बार सह तुमच्या स्क्रीनची वरची बाजू साफ करा"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"तुमचा चेहरा पूर्णपणे दृश्यमान असणे आवश्यक आहे"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"तुमचा चेहरा पूर्णपणे दृश्यमान असणे आवश्यक आहे"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"फेस मॉडेल तयार करू शकत नाही. पुन्हा प्रयत्न करा."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"गडद चष्मा डिटेक्ट केला. तुमचा चेहरा पूर्णपणे दृश्यमान असणे आवश्यक आहे."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"चेहर्‍यावरील आच्छादन डिटेक्ट केले. तुमचा चेहरा पूर्णपणे दृश्यमान असणे आवश्यक आहे."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"चेहरा पडताळू शकत नाही. हार्डवेअर उपलब्ध नाही."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 03cfbf5e928a..f9a0906329fa 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Buka Kunci Cap Jari"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Tidak boleh menggunakan penderia cap jari"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Lawati penyedia pembaikan."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Gagal menangkap data wajah dgn tepat. Cuba lagi."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah anda. Cuba lagi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Cuba pencahayaan yang lebih lembut."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Terlalu gelap. Cuba pencahayaan yang lebih cerah."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Jauhkan telefon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Dekatkan telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Tinggikan lagi telefon."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Rendahkan lagi telefon."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Alihkan telefon ke kiri."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Alihkan telefon ke kanan."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Cuba pencahayaan yang lebih cerah"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan telefon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan telefon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Tinggikan lagi telefon"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Rendahkan lagi telefon"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Gerakkan telefon ke kiri anda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Gerakkan telefon ke kanan anda"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Sila lihat terus pada peranti anda."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Letakkan wajah anda betul-betul di depan telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Gagal mengesan wajah anda. Pegang telefon anda pada paras mata."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Terlalu bnyk gerakan. Pegang telefon dgn stabil."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Sila daftarkan semula wajah anda."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu serupa, sila ubah lagak gaya anda."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pusingkan kepala anda kurang sedikit."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Sengetkan kepala anda kurang sedikit."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pusingkan kepala anda kurang sedikit."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Tidak dapat mengecam wajah. Cuba lagi."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Tukar sedikit kedudukan kepala anda"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Lihat terus pada telefon anda"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Lihat terus pada telefon anda"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Lihat terus pada telefon anda"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alih keluar apa saja yang melindungi wajah anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bahagian atas skrin anda, termasuk bar hitam"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Wajah anda mesti terlihat sepenuhnya"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Wajah anda mesti terlihat sepenuhnya"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Tidak dapat membuat model wajah anda. Cuba lagi."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Cermin mata gelap dikesan. Wajah anda mesti terlihat sepenuhnya."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Pelitup muka dikesan. Wajah anda mesti terlihat sepenuhnya."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tdk dpt sahkan wajah. Perkakasan tidak tersedia."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index cd8fdcda83b1..d5035a0f2a88 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"လက်ဗွေ အာရုံခံကိရိယာကို အသုံးပြု၍ မရပါ"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ပြုပြင်ရေး ဝန်ဆောင်မှုပေးသူထံသို့ သွားပါ။"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"မျက်နှာဒေတာ အမှန် မရိုက်ယူနိုင်ပါ၊ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"သင့်မျက်နှာနမူနာ ပြုလုပ်၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"အလွန် လင်းသည်။ အလင်းလျှော့ကြည့်ပါ။"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"အလွန်မှောင်သည်။ ပိုလင်းအောင် လုပ်ကြည့်ပါ။"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ဖုန်းကို အဝေးသို့ခွာပါ။"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ဖုန်းကို အနားသို့ ပိုတိုးပါ။"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ဖုန်းကို ပိုမြှင့်လိုက်ပါ။"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ဖုန်းကို အောက်ပိုနှိမ့်ပါ။"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ဖုန်းကို ဘယ်ဘက်သို့ရွှေ့ပါ။"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ဖုန်းကို ညာဘက်သို့ ရွှေ့ပါ။"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ပိုလင်းအောင် လုပ်ကြည့်ပါ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ဖုန်းကို အဝေးသို့ခွာပါ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ဖုန်းကို အနားသို့ပိုတိုးပါ"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ဖုန်းကို ပိုမြှင့်လိုက်ပါ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ဖုန်းကို အောက်ပိုနှိမ့်ပါ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ဖုန်းကို သင့်ဘယ်ဘက်သို့ ရွှေ့ပါ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ဖုန်းကို သင့်ညာဘက်သို့ ရွှေ့ပါ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"သင့်စက်ပစ္စည်းကို တည့်တည့်ကြည့်ပါ။"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"မျက်နှာကို ဖုန်းရှေ့တွင် တည့်အောင်ထားပါ။"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"သင့်မျက်နှာကို မမြင်ရပါ။ ဖုန်းကို မျက်လုံးနှင့် တစ်တန်းတည်းထား၍ ကိုင်ပါ။"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"လှုပ်လွန်းသည်။ ဖုန်းကို ငြိမ်ငြိမ်ကိုင်ပါ။"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"သင့်မျက်နှာကို ပြန်စာရင်းသွင်းပါ။"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ဆင်တူနေသည်၊ အမူအရာ ပြောင်းပါ။"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"သင့်ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"မျက်နှာကို မသိပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ခေါင်းအနေအထားကို အနည်းငယ်ပြောင်းပါ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"သင့်ဖုန်းကို တည့်တည့်ကြည့်ပါ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"သင့်ဖုန်းကို တည့်တည့်ကြည့်ပါ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"သင့်ဖုန်းကို တည့်တည့်ကြည့်ပါ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"သင့်မျက်နှာကို ကွယ်နေသည့်အရာအားလုံး ဖယ်ပါ။"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"အနက်ရောင်ဘားအပါအဝင် ဖန်သားပြင်ထိပ်ကို သန့်ရှင်းရေး လုပ်ပါ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"သင့်မျက်နှာကို အပြည့်အဝ မြင်ရရန်လိုအပ်သည်"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"သင့်မျက်နှာကို အပြည့်အဝ မြင်ရရန်လိုအပ်သည်"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"သင့်မျက်နှာနမူနာ ပြုလုပ်၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"အရောင်ရင့်သောမျက်မှန် တွေ့သည်။ သင့်မျက်နှာကို အပြည့်အဝ မြင်ရရန်လိုအပ်သည်။"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"မျက်နှာဖုံး တွေ့သည်။ သင့်မျက်နှာကို အပြည့်အဝ မြင်ရရန်လိုအပ်သည်။"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 11b544d8d448..f63dfefde7f3 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Opplåsing med fingeravtrykk"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Kan ikke bruke fingeravtrykkssensoren"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Gå til en reparasjonsleverandør."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Kunne ikke ta opp nøyaktige ansiktsdata Prøv på nytt"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan ikke opprette ansiktsmodellen. Prøv på nytt."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"For lyst. Prøv svakere belysning."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"For mørkt. Prøv sterkere belysning."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Flytt telefonen lengre unna"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Flytt telefonen nærmere."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Flytt telefonen høyere."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Flytt telefonen lavere."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Flytt telefonen til venstre."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Flytt telefonen til høyre."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv sterkere belysning"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Flytt telefonen lengre unna"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Flytt telefonen nærmere"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Flytt telefonen høyere"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Flytt telefonen lavere"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Flytt telefonen til venstre"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Flytt telefonen til høyre"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Se mer direkte på enheten din."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Hold ansiktet ditt rett foran telefonen."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kan ikke se ansiktet ditt. Hold telefonen i øyehøyde."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"For mye bevegelse. Hold telefonen stødig."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrer ansiktet ditt på nytt."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Kan ikke gjenkjenne ansiktet lenger. Prøv på nytt."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"For likt – endre posituren din."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vri hodet ditt litt mindre."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Vri hodet litt mindre."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vri hodet ditt litt mindre."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansiktet gjenkjennes ikke. Prøv på nytt."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Endre hodeposisjonen litt"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Se mer direkte på telefonen"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Se mer direkte på telefonen"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Se mer direkte på telefonen"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjern alt som skjuler ansiktet ditt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengjør den øverste delen av skjermen, inkludert den svarte linjen"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Ansiktet må være helt synlig"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Ansiktet må være helt synlig"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Kan ikke opprette ansiktsmodellen. Prøv på nytt."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Mørke briller er registrert. Ansiktet må være helt synlig."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Ansiktsdekke er registrert. Ansiktet må være helt synlig."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan ikke bekrefte ansikt. Utilgjengelig maskinvare."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index f98c0421344d..40e9160a9092 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"फिंगरप्रिन्ट अनलक"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"फिंगरप्रिन्ट सेन्सर प्रयोग गर्न मिल्दैन"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फिंगरप्रिन्ट सेन्सर मर्मत गर्ने सेवा प्रदायक कम्पनीमा सम्पर्क गर्नुहोस्।"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"अनुहारको सटीक डेटा खिच्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"तपाईंको फेस मोडेल सिर्जना गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ज्यादै चम्किलो। अझ मधुरो प्रकाश प्रयोग गरी हेर्नु…"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ज्यादै अँध्यारो छ। अझ बढी प्रकाशमा गई हेर्नुहोस्"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"फोन अझै पर सार्नुहोस्।"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"फोन अझै नजिक सार्नुहोस्।"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"फोन अझ माथि उठाउनुहोस्।"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"फोन अझै तल सार्नुहोस्।"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"फोन बायाँतिर सार्नुहोस्।"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"फोन दायाँतिर सार्नुहोस्।"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"अझ उज्यालो ठाउँमा गएर फोटो खिची हेर्नुहोस्"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"फोन अझै पर सार्नुहोस्"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"फोन अझै नजिक सार्नुहोस्"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"फोन अझ माथि उठाउनुहोस्"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"फोन अझै तल सार्नुहोस्"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"फोन आफ्नो बायाँतिर सार्नुहोस्"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"फोन आफ्नो दायाँतिर सार्नुहोस्"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"कृपया अझ सीधा गरी आफ्नो स्क्रिनमा हेर्नुहोस्।"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"आफ्नो अनुहार फोनको सीधा अगाडि पार्नुहोस्।"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"तपाईंको अनुहार देखिएन। तपाईंको फोन आफ्नो आँखाअघि राखी समात्नुहोस्।"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"अत्यधिक हल्लियो। फोन स्थिर राख्नुहोस्।"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्।"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"अनुहार उस्तै भयो, कृपया आफ्नो पोज बदल्नुहोस्।"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"आफ्नो टाउको केही कम झुकाउनुहोस्।"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"आफ्नो टाउको थोरै यताउता सार्नुहोस्"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तपाईंको अनुहार लुकाउने सबै कुरा लुकाउनुहोस्।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"कालो रङको पट्टीलगायत आफ्नो स्क्रिनको माथिल्लो भाग सफा गर्नुहोस्"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"तपाईंको अनुहार पूरै देखिनु पर्छ"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"तपाईंको अनुहार पूरै देखिनु पर्छ"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"तपाईंको फेस मोडेल सिर्जना गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"कालो चस्मा लगाइएको पाइयो। तपाईंको अनुहार पूरै देखिनु पर्छ।"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"अनुहार छोपिएको पाइयो। तपाईंको अनुहार पूरै देखिनु पर्छ।"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"अनुहार पुष्टि गर्न सकिएन। हार्डवेयर उपलब्ध छैन।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f7f28ddc32cf..1dbb6ff5aadd 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Ontgrendelen met vingerafdruk"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Kan vingerafdruksensor niet gebruiken"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ga naar een reparateur."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Geen accurate gegevens. Probeer het nog eens."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan gezichtsmodel niet maken. Probeer het opnieuw."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Overbelicht. Probeer een minder felle belichting."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Te donker. Probeer een fellere verlichting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Beweeg de telefoon verder weg."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Houd de telefoon dichterbij."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Houd de telefoon hoger."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Houd de telefoon lager."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Beweeg je telefoon meer naar links."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Beweeg je telefoon meer naar rechts."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer fellere verlichting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Houd de telefoon verder weg"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Houd de telefoon dichterbij"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Houd de telefoon hoger"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Houd de telefoon lager"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Beweeg de telefoon naar links"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Beweeg de telefoon naar rechts"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Kijk rechter naar je apparaat."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Houd je gezicht recht voor de telefoon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Je gezicht is niet te zien. Houd je telefoon op ooghoogte."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te veel beweging. Houd je telefoon stil."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registreer je gezicht opnieuw."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Herkent gezicht niet meer. Probeer het nog eens."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Lijkt te veel op elkaar. Verander je pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai je hoofd iets minder."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kantel je hoofd iets minder."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai je hoofd iets minder."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Gezicht niet herkend. Probeer het opnieuw."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Verander de positie van je hoofd een beetje"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kijk goed recht naar je telefoon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kijk goed recht naar je telefoon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Kijk goed recht naar je telefoon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Zorg dat je gezicht volledig zichtbaar is."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinig de bovenkant van je scherm, inclusief de zwarte balk"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Je gezicht moet geheel zichtbaar zijn"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Je gezicht moet geheel zichtbaar zijn"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Kan gezichtsmodel niet maken. Probeer het opnieuw."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Donkere bril waargenomen. Je gezicht moet geheel zichtbaar zijn."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Gezichtsbedekking waargenomen. Je gezicht moet geheel zichtbaar zijn."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan gezicht niet verifiëren. Hardware niet beschikbaar."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e1670f85a087..d70fc9b88cfe 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ୍"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ଏକ ମରାମତି କେନ୍ଦ୍ରକୁ ଭିଜିଟ୍ କରନ୍ତୁ।"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ମୁହଁର ଡାଟା କ୍ୟାପଚର୍ ହେଲାନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ଫେସର ମଡେଲ ତିଆରି କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ଅତ୍ୟଧିକ ଉଜ୍ଵଳ। କମ୍ ଉଜ୍ବଳକରଣରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ଅତ୍ୟଧିକ ଅନ୍ଧକାର। ଉଜ୍ବଳ ଲାଇଟ୍ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ଫୋନ୍‌କୁ ଟିକେ ଦୂରକୁ ନିଅନ୍ତୁ।"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ଫୋନ୍‌କୁ ପାଖକୁ ଆଣନ୍ତୁ।"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ଫୋନ୍‌କୁ ଉପରକୁ ଉଠାନ୍ତୁ।"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ଫୋନ୍‌କୁ ତଳକୁ ନିଅନ୍ତୁ।"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ବାମ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ଡାହାଣ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ଉଜ୍ଜ୍ୱଳ ଲାଇଟ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ଫୋନକୁ ଟିକେ ଦୂରକୁ ନିଅନ୍ତୁ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ଫୋନକୁ ପାଖକୁ ଆଣନ୍ତୁ"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ଫୋନକୁ ଉପରକୁ ନିଅନ୍ତୁ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ଫୋନକୁ ତଳକୁ ନିଅନ୍ତୁ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ଫୋନକୁ ଆପଣଙ୍କ ବାମ ପଟକୁ ନିଅନ୍ତୁ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ଫୋନକୁ ଆପଣଙ୍କ ଡାହାଣ ପଟକୁ ନିଅନ୍ତୁ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"ଦୟାକରି ଆପଣଙ୍କ ଡିଭାଇସ୍‌କୁ ସିଧାସଳଖ ଦେଖନ୍ତୁ।"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ଆପଣଙ୍କ ମୁହଁକୁ ଫୋନ୍ ସାମ୍ନାରେ ସିଧାସଳଖ ରଖନ୍ତୁ।"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ଆପଣଙ୍କ ଫେସ ଦେଖାଯାଉନାହିଁ। ଆପଣଙ୍କ ଫୋନକୁ ଆଖି ସିଧାରେ ଧରି ରଖନ୍ତୁ।"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ଅତ୍ୟଧିକ ଅସ୍ଥିର। ଫୋନ୍‍କୁ ସ୍ଥିର ଭାବେ ଧରନ୍ତୁ।"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"ଦୟାକରି ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍‍ରୋଲ୍ କରନ୍ତୁ।"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ଅତ୍ୟନ୍ତ ସମପରି, ଦୟାକରି ଆପଣଙ୍କର ପୋଜ୍ ବଦଳାନ୍ତୁ।"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ଆପଣଙ୍କ ମୁଣ୍ଡକୁ ଟିକିଏ କମ୍ ଟିଲ୍ଟ କରନ୍ତୁ।"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ଫେସ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ଆପଣଙ୍କ ମୁଣ୍ଡର ସ୍ଥିତି ସାମାନ୍ୟ ବଦଳାନ୍ତୁ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ଆପଣଙ୍କ ଫୋନକୁ ସମ୍ପୂର୍ଣ୍ଣ ସିଧା ଦେଖନ୍ତୁ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ଆପଣଙ୍କ ଫୋନକୁ ସମ୍ପୂର୍ଣ୍ଣ ସିଧା ଦେଖନ୍ତୁ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ଆପଣଙ୍କ ଫୋନକୁ ସମ୍ପୂର୍ଣ୍ଣ ସିଧା ଦେଖନ୍ତୁ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ଆପଣଙ୍କର ମୁହଁ ଲୁଚାଉଥିବା ଜିନିଷକୁ କାଢ଼ି ଦିଅନ୍ତୁ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"କଳା ବାର୍ ସମେତ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍‌ର ଶୀର୍ଷକୁ ସଫା କରନ୍ତୁ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ଆପଣଙ୍କ ଫେସ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଦେଖାଯିବା ଆବଶ୍ଯକ"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ଆପଣଙ୍କ ଫେସ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଦେଖାଯିବା ଆବଶ୍ଯକ"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ଫେସର ମଡେଲ ତିଆରି କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"କଳା ଚଷମା ଚିହ୍ନଟ କରାଯାଇଛି। ଆପଣଙ୍କ ଫେସ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଦେଖାଯିବା ଆବଶ୍ଯକ।"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ଫେସରେ କଭରିଂ ଚିହ୍ନଟ କରାଯାଇଛି। ଆପଣଙ୍କ ଫେସ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଦେଖାଯିବା ଆବଶ୍ଯକ।"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ମୁହଁ ଚିହ୍ନଟ କରିପାରିଲା ନାହିଁ। ହାର୍ଡୱେୟାର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 852d0f5f0244..cc3af05e200a 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ਮੁਰੰਮਤ ਪ੍ਰਦਾਨਕ \'ਤੇ ਜਾਓ।"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ਸਟੀਕ ਚਿਹਰਾ ਡਾਟਾ ਕੈਪਚਰ ਨਹੀਂ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਦਾ ਮਾਡਲ ਨਹੀਂ ਬਣਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ। ਹਲਕੀ ਚਮਕ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ਬਹੁਤ ਗੂੜ੍ਹਾ। ਤੇਜ਼ ਰੋਸ਼ਨੀ ਕਰਕੇ ਦੇਖੋ।"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ਫ਼ੋਨ ਨੂੰ ਦੂਰ ਲਿਜਾਓ।"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ਫ਼ੋਨ ਨੇੜੇ ਲਿਜਾਓ।"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਉੱਤੇ ਕਰੋ।"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਹੇਠਾਂ ਵੱਲ ਕਰੋ।"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ਫ਼ੋਨ ਨੂੰ ਖੱਬੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ਫ਼ੋਨ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ਤੇਜ਼ ਰੋਸ਼ਨੀ ਕਰ ਕੇ ਦੇਖੋ"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ਫ਼ੋਨ ਨੂੰ ਦੂਰ ਲਿਜਾਓ"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ਫ਼ੋਨ ਨੇੜੇ ਲਿਜਾਓ"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਉੱਤੇ ਲਿਜਾਓ"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਹੇਠਾਂ ਲਿਜਾਓ"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ਫ਼ੋਨ ਨੂੰ ਆਪਣੇ ਖੱਬੇ ਪਾਸੇ ਲਿਜਾਓ"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ਫ਼ੋਨ ਨੂੰ ਆਪਣੇ ਸੱਜੇ ਪਾਸੇ ਲਿਜਾਓ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"ਕਿਰਪਾ ਕਰਕੇ ਸਿੱਧਾ ਆਪਣੇ ਡੀਵਾਈਸ ਵੱਲ ਦੇਖੋ।"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ਆਪਣਾ ਚਿਹਰਾ ਫ਼ੋਨ ਦੇ ਬਿਲਕੁਲ ਸਾਹਮਣੇ ਰੱਖੋ।"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਨਹੀਂ ਦਿਸ ਰਿਹਾ। ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਅੱਖਾਂ ਦੀ ਸੀਧ ਵਿੱਚ ਰੱਖੋ।"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਹਿਲਜੁਲ। ਫ਼ੋਨ ਨੂੰ ਸਥਿਰ ਰੱਖੋ।"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਚਿਹਰਾ ਦੁਬਾਰਾ ਦਰਜ ਕਰੋ।"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ਬਹੁਤ ਮਿਲਦਾ-ਜੁਲਦਾ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਅੰਦਾਜ਼ ਬਦਲੋ।"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ਆਪਣੇ ਸਿਰ ਨੂੰ ਥੋੜ੍ਹਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ਆਪਣੇ ਸਿਰ ਨੂੰ ਥੋੜ੍ਹਾ ਹਿਲਾਓ"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ਸਿੱਧਾ ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ਸਿੱਧਾ ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ਸਿੱਧਾ ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਲੁਕਾਉਣ ਵਾਲੀ ਕੋਈ ਵੀ ਚੀਜ਼ ਹਟਾਓ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ਕਾਲੀ ਪੱਟੀ ਸਮੇਤ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ਤੁਹਾਡਾ ਪੂਰਾ ਚਿਹਰਾ ਦਿਸਣਾ ਲਾਜ਼ਮੀ ਹੈ"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ਤੁਹਾਡਾ ਪੂਰਾ ਚਿਹਰਾ ਦਿਸਣਾ ਲਾਜ਼ਮੀ ਹੈ"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਦਾ ਮਾਡਲ ਨਹੀਂ ਬਣਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ਧੁੱਪ ਦੀਆਂ ਐਨਕਾਂ ਦਾ ਪਤਾ ਲੱਗਾ। ਤੁਹਾਡਾ ਪੂਰਾ ਚਿਹਰਾ ਦਿਸਣਾ ਲਾਜ਼ਮੀ ਹੈ।"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ਚਿਹਰਾ ਢੱਕਿਆ ਹੋਣ ਦਾ ਪਤਾ ਲੱਗਾ। ਤੁਹਾਡਾ ਪੂਰਾ ਚਿਹਰਾ ਦਿਸਣਾ ਲਾਜ਼ਮੀ ਹੈ।"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ਚਿਹਰੇ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਹੋ ਸਕੀ। ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9d08c66331ce..2e491b385910 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Odblokowywanie odciskiem palca"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nie można użyć czytnika linii papilarnych"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Odwiedź serwis."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Nie udało się zarejestrować danych twarzy. Spróbuj ponownie."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nie można utworzyć modelu twarzy. Spróbuj ponownie."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Zbyt jasno. Spróbuj przy słabszym świetle."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Zbyt ciemno. Spróbuj w jaśniejszym świetle."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Odsuń telefon."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Przybliż telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Przesuń telefon wyżej."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Przesuń telefon niżej."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Przesuń telefon w lewo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Przesuń telefon w prawo."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Spróbuj w jaśniejszym świetle"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Odsuń telefon"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Przybliż telefon"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Przesuń telefon wyżej"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Przesuń telefon niżej"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Przesuń telefon w lewo"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Przesuń telefon w prawo"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Patrz prosto na urządzenie."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Ustaw twarz dokładnie na wprost telefonu."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie widzę twarzy. Trzymaj telefon na wysokości oczu."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Telefon się porusza. Trzymaj go nieruchomo."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Zarejestruj swoją twarz ponownie."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Za mała różnica. Zmień pozycję."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Trochę mniej obróć głowę."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Trochę mniej pochyl głowę."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Trochę mniej obróć głowę."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Nie rozpoznaję twarzy. Spróbuj ponownie."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Lekko zmień położenie głowy"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Patrz prosto na telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Patrz prosto na telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Patrz prosto na telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Usuń wszystko, co zasłania Ci twarz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Wyczyść górną krawędź ekranu, w tym czarny pasek"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Twarz musi być widoczna w całości"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Twarz musi być widoczna w całości"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nie można utworzyć modelu twarzy. Spróbuj ponownie."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Wykryto ciemne okulary. Twarz musi być widoczna w całości."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Wykryto zasłonę twarzy. Twarz musi być widoczna w całości."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nie można zweryfikować twarzy. Sprzęt niedostępny."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 527b9225213e..029099b65e8d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueio por impressão digital"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Não foi possível usar o sensor de impressão digital"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Dados precisos não capturados. Tente novamente."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Muito escuro. Use uma iluminação mais clara."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Afaste o smartphone."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Aproxime o smartphone."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mova o smartphone para cima."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mova o smartphone para baixo."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mova o smartphone para a esquerda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mova o smartphone para a direita."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mova o smartphone para baixo"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mova o smartphone para a esquerda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mova o smartphone para a direita"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Deixe o rosto diretamente na frente do smartphone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Rosto não detectado. Segure o smartphone na altura dos olhos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Muito movimento. Não mova o smartphone."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registre seu rosto novamente."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Não foi possível reconhecer o rosto Tente de novo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Mude a posição da cabeça ligeiramente"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe mais diretamente para o smartphone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe mais diretamente para o smartphone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Olhe mais diretamente para o smartphone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Seu rosto precisa estar completamente visível"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Seu rosto precisa estar completamente visível"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Falha ao criar o modelo de rosto. Tente de novo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Óculos escuros detectados. Seu rosto precisa estar completamente visível."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Máscara detectada. Seu rosto precisa estar completamente visível."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 93516bd2024c..3abe9b3ba115 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueio por impressão digital"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Não é possível utilizar o sensor de impressões digitais"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visite um fornecedor de serviços de reparação."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Imp. capt. dados rosto precisos. Tente novamente."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossível criar modelo de rosto. Tente novamente."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado clara. Experimente uma luz mais suave."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Demasiado escura. Experimente local com mais luz."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Afaste ainda mais o telemóvel."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Aproxime o telemóvel."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mova o telemóvel mais para cima."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mova o telemóvel mais para baixo."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mova o telemóvel para a esquerda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mova o telemóvel para a direita."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Experimente um local com mais luz"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste ainda mais o telemóvel"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o telemóvel"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o telemóvel mais para cima"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mova o telemóvel mais para baixo"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mova o telemóvel para a sua esquerda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mova o telemóvel para a sua direita"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Posicione o rosto em frente ao telemóvel."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Não é possível ver o seu rosto. Mantenha o telemóvel ao nível dos olhos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Demasiado movimento. Mantenha o telemóvel firme."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Volte a inscrever o rosto."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Impossível reconhecer o rosto. Tente novamente."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecida, mude de pose."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Rode a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Rode a cabeça um pouco menos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Impossível reconhecer o rosto. Tente novamente."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Altere ligeiramente a posição da sua cabeça"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe mais diretamente para o telemóvel"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe mais diretamente para o telemóvel"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Olhe mais diretamente para o telemóvel"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo o que esteja a ocultar o seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior do ecrã, incluindo a barra preta."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"O seu rosto tem de estar completamente visível"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"O seu rosto tem de estar completamente visível"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Não é possível criar o seu modelo de rosto. Tente novamente."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Óculos escuros detetados. O seu rosto tem de estar completamente visível."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Cobertura facial detetada. O seu rosto tem de estar completamente visível."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Não pode validar o rosto. Hardware não disponível."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 527b9225213e..029099b65e8d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Desbloqueio por impressão digital"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Não foi possível usar o sensor de impressão digital"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Dados precisos não capturados. Tente novamente."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Muito escuro. Use uma iluminação mais clara."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Afaste o smartphone."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Aproxime o smartphone."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mova o smartphone para cima."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mova o smartphone para baixo."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mova o smartphone para a esquerda."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mova o smartphone para a direita."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mova o smartphone para baixo"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mova o smartphone para a esquerda"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mova o smartphone para a direita"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Deixe o rosto diretamente na frente do smartphone."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Rosto não detectado. Segure o smartphone na altura dos olhos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Muito movimento. Não mova o smartphone."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registre seu rosto novamente."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Não foi possível reconhecer o rosto Tente de novo."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Mude a posição da cabeça ligeiramente"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe mais diretamente para o smartphone"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe mais diretamente para o smartphone"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Olhe mais diretamente para o smartphone"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Seu rosto precisa estar completamente visível"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Seu rosto precisa estar completamente visível"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Falha ao criar o modelo de rosto. Tente de novo."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Óculos escuros detectados. Seu rosto precisa estar completamente visível."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Máscara detectada. Seu rosto precisa estar completamente visível."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 15d1a67ecdc5..f606eb222297 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Deblocare cu amprenta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nu se poate folosi senzorul de amprentă"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizitați un furnizor de servicii de reparații."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Nu s-a putut fotografia fața cu precizie. Încercați din nou."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nu se poate crea modelul facial. Reîncercați."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Prea luminos. Încercați o lumină mai slabă."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Prea întunecat. Încercați o lumină mai puternică."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Mutați telefonul mai departe."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Mutați telefonul mai aproape."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Mutați telefonul mai sus."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Mutați telefonul mai jos."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Mutați telefonul spre stânga."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Mutați telefonul spre dreapta."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Încercați o lumină mai puternică"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Mutați telefonul mai departe"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Mutați telefonul mai aproape"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Mutați telefonul mai sus"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Mutați telefonul mai jos"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Mutați telefonul spre stânga"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Mutați telefonul spre dreapta"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Priviți mai direct spre dispozitiv."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Stați cu capul direct în fața telefonului."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nu vi se vede fața. Țineți telefonul la nivelul ochilor."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Prea multă mișcare. Țineți telefonul nemișcat."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Reînregistrați-vă chipul."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Prea asemănător, schimbați poziția."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Întoarceți capul mai puțin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Înclinați capul mai puțin."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Întoarceți capul mai puțin."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Chipul nu a fost recunoscut. Reîncercați."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Schimbați ușor poziția capului"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Priviți direct spre telefon"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Priviți direct spre telefon"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Priviți direct spre telefon"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eliminați orice vă ascunde chipul."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curățați partea de sus a ecranului, inclusiv bara neagră"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Chipul trebuie să fie vizibil în totalitate"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Chipul trebuie să fie vizibil în totalitate"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Nu se poate crea modelul facial. Reîncercați."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"S-au detectat ochelari de culoare închisă. Chipul trebuie să fie vizibil în totalitate."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"S-a detectat un articol care acoperă chipul. Chipul trebuie să fie vizibil în totalitate."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nu se poate confirma fața. Hardware-ul nu este disponibil."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 845f89d6352c..072b1cfc691c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Разблокировка по отпечатку пальца"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Невозможно использовать сканер отпечатков пальцев"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Обратитесь в сервисный центр."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Не удалось собрать данные. Повторите попытку."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Невозможно создать модель лица. Повторите попытку."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Слишком светло. Сделайте освещение менее ярким."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Слишком темно. Сделайте освещение ярче."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Переместите телефон дальше."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Переместите телефон ближе."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Переместите телефон выше."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Переместите телефон ниже."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Переместите телефон влево."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Переместите телефон вправо."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Сделайте освещение ярче."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Переместите телефон дальше от лица."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Переместите телефон ближе к лицу."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Переместите телефон выше."</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Переместите телефон ниже."</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Переместите телефон левее."</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Переместите телефон правее."</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Смотрите прямо на устройство."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Держите телефон прямо перед лицом."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Вашего лица не видно. Держите телефон на уровне глаз."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Не перемещайте устройство. Держите его неподвижно."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторите попытку."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Не удалось распознать лицо. Повторите попытку."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Слишком похожее выражение лица. Измените позу."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Держите голову ровнее."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не наклоняйте голову слишком сильно."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Держите голову ровнее."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Не удалось распознать лицо. Повторите попытку."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Немного измените положение головы."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Смотрите прямо на телефон."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Смотрите прямо на телефон."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Смотрите прямо на телефон."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ваше лицо плохо видно."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Протрите верхнюю часть экрана (в том числе черную панель)."</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Лицо должно быть полностью видно."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Лицо должно быть полностью видно."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Невозможно создать модель лица. Повторите попытку."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Распознаны темные очки. Лицо должно быть полностью видно."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Часть лица закрыта. Оно должно быть полностью видно."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Не удалось распознать лицо. Сканер недоступен."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index f0cde1dad419..e8d2be9a87cf 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ඇඟිලි සලකුණු අගුළු හැරීම"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ඇඟිලි සලකුණු සංවේදකය භාවිත කළ නොහැකිය"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"අළුත්වැඩියා සැපයුම්කරුවෙකු බලන්න."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"නිරවද්‍ය මුහුණු දත්ත ගත නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"ඔබගේ මුහුණු ආකෘතිය තැනිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"දීප්තිය වැඩියි. තවත් මඳ ආලෝකය උත්සාහ කරන්න."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"ඉතා අඳුරුයි. තවත් දීප්තිමත් ආලෝකය උත්සාහ කරන්න."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"දුරකථනය තවත් දුරට ගෙන යන්න."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"දුරකථනය තවත් සමීපව ගෙන යන්න."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"දුරකථනය ඉහළට ගෙන යන්න."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"දුරකථනය පහළට ගෙන යන්න."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"දුරකථනය වමට ගෙන යන්න."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"දුරකථනය දකුණට ගෙන යන්න."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"තවත් දීප්තිමත් ආලෝකය උත්සාහ කරන්න"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"දුරකථනය තවත් ඈතට ගෙන යන්න"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"දුරකථනය තවත් සමීපයට ගෙන එන්න"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"දුරකථනය තවත් ඉහළට ගෙන යන්න"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"දුරකථනය තවත් පහළට ගෙන යන්න"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"දුරකථනය ඔබගේ වම් පසට ගෙන යන්න"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"දුරකථනය ඔබගේ දකුණු පසට ගෙන යන්න"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"ඔබේ උපාංගය වෙත තවත් ඍජුව බලන්න."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"ඔබේ මුහුණ දුරකථනයට සෘජුවම ඉදිරියෙන් ස්ථානගත කරන්න."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ඔබගේ මුහුණ දැකිය නොහැකිය. ඔබගේ දුරකථනය ඇස් මට්ටමින් අල්ලා ගන්න."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"චලනය ඉතා වැඩියි. දුරකථනය ස්ථිරව අල්ලා සිටින්න."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"ඔබේ මුහුණ යළි ලියාපදිංචි කරන්න."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ඉතා සමානයි, ඔබේ හැඩ ගැසීම වෙනස් කරන්න."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ඔබගේ හිස ටිකක් අඩුවෙන් ඇල කරන්න."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"මුහුණ හඳුනා ගත නොහැකිය. නැවත උත්සාහ කරන්න."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"ඔබගේ හිසෙහි පිහිටීම මදක් වෙනස් කරන්න"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ඔබගේ දුරකථනය දෙස වඩාත් ඍජුව බලන්න"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ඔබගේ දුරකථනය දෙස වඩාත් ඍජුව බලන්න"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"ඔබගේ දුරකථනය දෙස වඩාත් ඍජුව බලන්න"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ඔබේ මුහුණ සඟවන කිසිවක් ඉවත් කරන්න."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"කලු තීරුව ඇතුළුව, ඔබේ තිරයෙහි මුදුන පිරිසිදු කරන්න"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ඔබගේ මුහුණ සම්පූර්ණයෙන් දෘශ්‍යමාන විය යුතුය"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ඔබගේ මුහුණ සම්පූර්ණයෙන් දෘශ්‍යමාන විය යුතුය"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"ඔබගේ මුහුණු ආකෘතිය තැනිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"අඳුරු කණ්ණාඩි අනාවරණය කර ගන්නා ලදි. ඔබගේ මුහුණ සම්පූර්ණයෙන් දෘශ්‍යමාන විය යුතුය."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"මුහුණු ආවරණය අනාවරණය කර ගන්නා ලදි. ඔබගේ මුහුණ සම්පූර්ණයෙන් දෘශ්‍යමාන විය යුතුය."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"මුහුණ සත්‍යාපනය කළ නොහැක. දෘඩාංගය නොමැත."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 8a468fbc9a7a..ce8837b14011 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Odomknutie odtlačkom prsta"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Senzor odtlačkov prstov nie je možné používať"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštívte poskytovateľa opráv."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Nepodarilo sa nasnímať presné údaje o tvári. Skúste to znova."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Model tváre sa nedá vytvoriť. Skúste to znova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Príliš veľa svetla. Skúste jemnejšie osvetlenie."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Príliš veľká tma. Skúste lepšie osvetlenie."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Oddiaľte telefón."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Priblížte telefón."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Posuňte telefón vyššie."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Posuňte telefón nižšie."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Posuňte telefón doľava."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Posuňte telefón doprava."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Skúste lepšie osvetlenie"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Oddiaľte telefón"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Priblížte telefón"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Posuňte telefón vyššie"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Posuňte telefón nižšie"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Posuňte telefón doľava"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Posuňte telefón doprava"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Pozrite sa priamejšie na zariadenie."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Umiestnite svoju tvár priamo pred telefón."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie je vidieť vašu tvár. Držte telefón na úrovni očí."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Priveľa pohybu. Nehýbte telefónom."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova zaregistrujte svoju tvár."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Príliš rovnaké, zmeňte postoj."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Otočte hlavu o niečo menej."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nakloňte hlavu trocha menej."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Otočte hlavu o niečo menej."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Tvár sa nedá rozpoznať. Skúste to znova."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Trocha zmeňte pozíciu hlavy"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Pozrite sa na telefón priamejšie"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Pozrite sa na telefón priamejšie"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Pozrite sa na telefón priamejšie"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstráňte všetko, čo vám zakrýva tvár."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vyčistite hornú časť obrazovky vrátane čierneho panela"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Musí vám byť vidieť celú tvár"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Musí vám byť vidieť celú tvár"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Model tváre sa nedá vytvoriť. Skúste to znova."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Boli rozpoznané tmavé okuliare. Musí vám byť vidieť celú tvár."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Bolo rozpoznané rúško. Musí vám byť vidieť celú tvár."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tvár sa nedá overiť. Hardvér nie je k dispozícii."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9a2941f7ce54..fd1070c59a64 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Odklepanje s prstnim odtisom"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Tipala prstnih odtisov ni mogoče uporabiti"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Obiščite ponudnika popravil."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Točnih podatkov o obrazu ni bilo mogoče zajeti. Poskusite znova."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Modela obraza ni mogoče ustvariti. Poskusite znova."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Pretemno. Poskusite z močnejšo osvetlitvijo."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Telefon nekoliko odmaknite."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Bolj približajte telefon."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Telefon pomaknite višje."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Telefon premaknite nižje."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Telefon premaknite v levo."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Telefon premaknite v desno."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Poskusite z močnejšo osvetlitvijo."</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefon nekoliko odmaknite."</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Bolj približajte telefon."</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefon premaknite višje."</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Telefon premaknite nižje."</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Telefon premaknite v svojo levo."</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Telefon premaknite v svojo desno."</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Glejte bolj naravnost v napravo."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Obraz nastavite naravnost pred telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Obraz ni viden. Držite telefon v višini oči."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Preveč se premikate. Držite telefon pri miru."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova registrirajte svoj obraz."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Obraz nastavite bolj naravnost."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Glejte malce bolj naravnost."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Obraza ni mogoče prepoznati. Poskusite znova."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nekoliko spremenite položaj glave."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Glejte bolj naravnost v telefon."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Glejte bolj naravnost v telefon."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Glejte bolj naravnost v telefon."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Umaknite vse, kar vam morda zakriva obraz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrhnji del zaslona, vključno s črno vrstico"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Videti se mora cel obraz."</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Videti se mora cel obraz."</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Modela obraza ni mogoče ustvariti. Poskusite znova."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Zaznana so temna očala. Videti se mora cel obraz."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Zaznano je, da je obraz prekrit. Videti se mora cel obraz."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Obraza ni mogoče preveriti. Str. opr. ni na voljo."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 5792e152d94a..1847f2d87058 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Shkyçja me gjurmën e gishtit"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Sensori i gjurmës së gishtit nuk mund të përdoret"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizito një ofrues të shërbimit të riparimit."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"S\'mund të regjistroheshin të dhëna të sakta të fytyrës. Provo përsëri."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Modeli i fytyrës nuk krijohet. Provo sërish."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Me shumë ndriçim. Provo një ndriçim më të butë."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Shumë i errët. Provo një ndriçim më të fortë."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Lëvize telefonin më larg."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Afroje telefonin."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Ngrije telefonin më lart."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Ule telefonin më poshtë."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Lëvize telefonin majtas."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Lëvize telefonin djathtas"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Provo një ndriçim më të fortë"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Lëvize telefonin më larg"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Lëvize telefonin më afër"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Lëvize telefonin më lart"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Lëvize telefonin më poshtë"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Lëvize telefonin në të majtën tënde"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Lëvize telefonin në të djathtën tënde"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Shiko më drejt në pajisjen tënde."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Pozicionoje fytyrën tënde direkt përpara telefonit."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Fytyra jote nuk mund të shihet. Mbaje telefonin në nivelin e syve."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ka shumë lëvizje. Mbaje telefonin të palëvizur."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Regjistroje përsëri fytyrën tënde."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Tepër e ngjashme, ndrysho pozën"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Ktheje kokën pak më pak."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Anoje kokën më pak."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Ktheje kokën pak më pak."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Fytyra nuk mund të njihet. Provo sërish."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ndrysho pak pozicionin e kokës"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Shiko më shumë drejtpërdrejt telefonit"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Shiko më shumë drejtpërdrejt telefonit"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Shiko më shumë drejtpërdrejt telefonit"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hiq gjithçka që fsheh fytyrën tënde."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pastro kreun e ekranit, duke përfshirë shiritin e zi"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Fytyra jote duhet të jetë plotësisht e dukshme"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Fytyra jote duhet të jetë plotësisht e dukshme"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Modeli i fytyrës nuk krijohet. Provo sërish."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"U zbuluan syze të errëta. Fytyra jote duhet të jetë plotësisht e dukshme."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"U zbulua mbulim i fytyrës. Fytyra jote duhet të jetë plotësisht e dukshme."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Fytyra s\'mund të verifikohet. Hardueri nuk ofrohet."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 9a8eaa2471c9..2fb6ac120d12 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -635,26 +635,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Откључавање отиском прста"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Не можете да користите сензор за отисак прста"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетите добављача за поправке."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Снимање лица није успело. Пробајте поново."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Прављење модела лица није успело. Пробајте поново."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Превише је светло. Пробајте са слабијим осветљењем."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Претамно је. Пробајте са јачим осветљењем."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Удаљите телефон."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Приближите телефон."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Померите телефон нагоре."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Померите телефон надоле."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Померите телефон улево."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Померите телефон удесно."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте са јачим осветљењем"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Удаљите телефон"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Приближите телефон"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Померите телефон нагоре"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Померите телефон надоле"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Померите телефон улево"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Померите телефон удесно"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Гледајте право у уређај."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Поставите лице директно испред телефона"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не види се лице. Држите телефон у висини очију."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Много се померате. Држите телефон мирно."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Поново региструјте лице."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Више не може да се препозна лице. Пробајте поново."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Превише је слично, промените позу."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Мало мање померите главу."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Мало мање нагните главу."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Мало мање померите главу."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Лице није препознато. Пробајте поново."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Мало померите главу"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледајте право у телефон"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледајте право у телефон"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Гледајте право у телефон"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Уклоните све што вам заклања лице."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистите горњи део екрана, укључујући црну траку"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Лице мора да буде потпуно видљиво"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Лице мора да буде потпуно видљиво"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Прављење модела лица није успело. Пробајте поново."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Откривене су тамне наочари. Лице мора да буде потпуно видљиво."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Откривено је прекривање лица. Лице мора да буде потпуно видљиво."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Провера лица није успела. Хардвер није доступан."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a25649413503..40a8c6129038 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingeravtryckslås"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Det går inte att använda fingeravtryckssensorn"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besök ett reparationsställe."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Det gick inte att fånga ansiktsdata. Försök igen."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ansiktsmodellen kunde inte skapas. Försök igen."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Det är för ljust. Testa lägre belysning."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Det är för mörkt. Testa med bättre belysning."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Flytta mobilen längre bort."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"För mobilen närmare."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Höj mobilen."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Sänk mobilen."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Flytta mobilen åt vänster."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Flytta mobilen åt höger."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Testa med bättre belysning"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Flytta telefonen längre bort"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"För telefonen närmare"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Höj telefonen"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Sänk telefonen"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Flytta telefonen åt vänster"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Flytta telefonen åt höger"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Titta rakt på enheten."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Ha ansiktet direkt framför telefonen."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ansiktet syns inte. Håll telefonen i ögonhöjd."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"För mycket rörelse. Håll mobilen stilla."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrera ansiktet på nytt."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"För likt. Ändra ansiktsposition."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vrid mindre på huvudet."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Vinkla huvudet mindre."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vrid mindre på huvudet."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansiktet kändes inte igen. Försök igen."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Rör lite på huvudet."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Titta rakt på telefonen"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Titta rakt på telefonen"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Titta rakt på telefonen"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ta bort allt som täcker ansiktet."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengör skärmens överkant, inklusive det svarta fältet"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Hela ansiktet måste synas"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Hela ansiktet måste synas"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Ansiktsmodellen kunde inte skapas. Försök igen."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Mörka glasögon identifierades. Hela ansiktet måste synas."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Något som täcker ansiktet identifierades. Hela ansiktet måste synas."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansiktsverifiering går ej. Otillgänglig maskinvara."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d9684ecc51d7..a3a74619658c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Kufungua kwa Alama ya Kidole"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Imeshindwa kutumia kitambua alama ya kidole"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Tembelea mtoa huduma za urekebishaji."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Imeshindwa kunasa data sahihi ya uso. Jaribu tena."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Imeshindwa kuunda muundo wa uso wako. Jaribu tena."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Inang\'aa mno. Jaribu mwangaza hafifu"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Hakuna mwangaza wa kutosha. Jaribu kuongeza mwangaza."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Sogeza simu mbali kiasi."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Sogeza simu karibu."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Sogeza simu juu zaidi."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Sogeza simu chini."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Sogeza simu upande wa kushoto."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Sogeza simu upande wa kulia."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Jaribu kuongeza mwangaza"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Sogeza simu mbali kiasi"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Sogeza simu karibu"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Sogeza simu juu zaidi"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Sogeza simu chini"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Sogeza simu upande wako wa kushoto"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Sogeza simu upande wako wa kulia"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Tafadhali angalia kifaa chako moja kwa moja."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Weka uso wako moja kwa moja mbele ya simu."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Imeshindwa kuona uso wako. Shikilia simu yako katika usawa wa macho."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Inatikisika sana. Ishike simu iwe thabiti."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Tafadhali sajili uso wako tena."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Haiwezi tena kutambua uso. Jaribu tena."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Inafanana sana, tafadhali badilisha mkao wako."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Geuza kichwa chako kidogo."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inamisha kichwa chako kiasi."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Geuza kichwa chako kidogo."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Imeshindwa kutambua uso. Jaribu tena."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Badilisha nafasi ya kichwa chako kidogo"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Angalia simu yako moja kwa moja"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Angalia simu yako moja kwa moja"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Angalia simu yako moja kwa moja"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ondoa kitu chochote kinachoficha uso wako."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Safisha sehemu ya juu ya skrini yako, ikiwa ni pamoja na upau mweusi"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Ni lazima uso wako wote uonekane"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Ni lazima uso wako wote uonekane"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Imeshindwa kuunda muundo wa uso wako. Jaribu tena."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Vioo vyeusi vimetambuliwa. Ni lazima uso wako wote uonekane."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Kifuniko cha uso kimetambuliwa. Ni lazima uso wako wote uonekane."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imeshindwa kuthibitisha uso. Maunzi hayapatikani."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6c889f9a2378..f657bd7620b5 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"கைரேகை அன்லாக்"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"கைரேகை சென்சாரைப் பயன்படுத்த முடியவில்லை"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"பழுதுபார்ப்புச் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"முகம் தெளிவாகப் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"முகத் தோற்றம் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"அதிக ஒளிர்வு. மிதமான ஒளியில் முயலவும்."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"இருட்டாக உள்ளது. பிரகாசமான ஒளியில் முயலவும்."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"மொபைலை முகத்தில் இருந்து தள்ளிப் பிடிக்கவும்."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"மொபைலை அருகில் நகர்த்தவும்."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"மொபைலை மேலே நகர்த்தவும்."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"மொபைலைக் கீழே நகர்த்தவும்."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"மொபைலை இடப்புறம் நகர்த்தவும்."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"மொபைலை வலப்புறம் நகர்த்தவும்."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"பிரகாசமான ஒளியில் முயலவும்"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"மொபைலை முகத்தில் இருந்து தள்ளிப் பிடிக்கவும்"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"மொபைலை அருகில் நகர்த்தவும்"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"மொபைலை மேலே நகர்த்தவும்"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"மொபைலைக் கீழே நகர்த்தவும்"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"மொபைலை இடதுபுறம் நகர்த்தவும்"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"மொபைலை வலதுபுறம் நகர்த்தவும்"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"முழுமுகம் தெரியுமாறு நேராகப் பார்க்கவும்."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"முகத்தை மொபைலுக்கு நேராக வைக்கவும்."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"முகம் சரியாகத் தெரியவில்லை. மொபைலைக் கண்களுக்கு நேராகப் பிடிக்கவும்."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"அதிகமாக அசைகிறது. மொபைலை அசைக்காமல் பிடிக்கவும்."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"உங்கள் முகத்தை மீண்டும் பதிவுசெய்யுங்கள்."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"மீண்டும் அதே போஸ் தருகிறீர்கள், வேறு முயலுங்கள்."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"தலையை லேசாகத் திருப்பவும்."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"உங்கள் தலையை லேசாகச் சாய்க்கவும்."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"உங்கள் தலையைச் சற்றுத் திருப்பவும்."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"முகத்தை அடையாளம் காண இயலவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"தலையின் நிலையைச் சிறிதளவு மாற்றவும்"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"உங்கள் மொபைலை நேராகப் பார்க்கவும்"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"உங்கள் மொபைலை நேராகப் பார்க்கவும்"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"உங்கள் மொபைலை நேராகப் பார்க்கவும்"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"உங்கள் முகத்தை மறைக்கும் அனைத்தையும் நீக்குக."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"திரையையும் அதிலுள்ள கருப்புப் பட்டியையும் சுத்தம் செய்யவும்"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"உங்கள் முகத்தை முழுமையாகக் காட்டவும்"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"உங்கள் முகத்தை முழுமையாகக் காட்டவும்"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"முகத் தோற்றம் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"அடர் நிறக் கண்ணாடிகள் கண்டறியப்பட்டுள்ளது. உங்கள் முகத்தை முழுமையாகக் காட்டவும்."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"முகம் மறைக்கப்பட்டுள்ளது. உங்கள் முகத்தை முழுமையாகக் காட்டவும்."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"முகத்தைச் சரிபார்க்க இயலவில்லை. வன்பொருள் இல்லை."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7bf639d195de..38d9d9aee8b8 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"వేలిముద్ర అన్‌లాక్"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"వేలిముద్ర సెన్సార్‌ను ఉపయోగించడం సాధ్యం కాదు"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"రిపెయిర్ ప్రొవైడర్‌ను సందర్శించండి."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"ముఖం డేటా సరిగ్గా రాలేదు. మళ్లీ ప్రయత్నించండి."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"మీ ఫేస్‌మోడల్ క్రియేషన్ కుదరదు. మళ్లీ ట్రై చేయండి."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"వెలుతురు అధికంగా ఉంది. తక్కువ ఉండేలా చూడండి."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"చాలా చీకటిగా ఉంది. బాగా వెలుతురులో ప్రయత్నించండి."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"ఫోన్‌ను కాస్త దూరంగా పట్టుకోండి."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"ఫోన్‌ను దగ్గరగా పట్టుకోండి"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ఫోన్‌ను పైకి పట్టుకోండి."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ఫోన్‌ను కిందికి దించండి."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"ఫోన్‌ను ఎడమవైపునకు జరపండి."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"ఫోన్‌ను కుడివైపునకు జరపండి."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ప్రకాశవంతమైన లైటింగ్‌లో ట్రై చేయండి"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ఫోన్‌ను కాస్త దూరంగా జరపండి"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ఫోన్‌ను దగ్గరగా పట్టుకోండి"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ఫోన్‌ను పైకి పట్టుకోండి"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ఫోన్‌ను కిందికి దించండి"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"ఫోన్‌ను మీ ఎడమ వైపునకు జరపండి"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"ఫోన్‌ను మీ కుడి వైపునకు జరపండి"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"దయచేసి మీ పరికరం వైపు మరింత నేరుగా చూడండి."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"మీ ముఖాన్ని ఫోన్‌కు ఎదురుగా ఉంచండి."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"మీ ముఖం కనిపించడం లేదు. మీ ఫోన్‌ను కంటి స్థాయిలో పట్టుకోండి."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"బాగా కదుపుతున్నారు. ఫోన్‌ను స్థిరంగా పట్టుకోండి"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"దయచేసి మీ ముఖాన్ని మళ్లీ నమోదు చేయండి."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ఒకే మాదిరిగా ఉంది, దయచేసి భంగిమను మార్చండి."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"మీ తలను కొంచెం తక్కువగా వంపండి."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"మీ తలను ఎడమ/కుడి వైపుగా ఇంకాస్త తిప్పండి."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ముఖం గుర్తించబడలేదు. మళ్లీ ట్రై చేయండి."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"మీ తల స్థానాన్ని కొద్దిగా మార్చండి"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"మీ ముఖానికి అడ్డుగా ఉన్నవాటిని తీసివేస్తుంది."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"నల్లని పట్టీతో సహా మీ స్క్రీన్ పైభాగం అంతటినీ శుభ్రంగా తుడవండి"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"మీ ముఖం పూర్తిగా కనిపించాలి"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"మీ ముఖం పూర్తిగా కనిపించాలి"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"మీ ఫేస్‌మోడల్ క్రియేషన్ కుదరదు. మళ్లీ ట్రై చేయండి."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"డార్క్ గ్లాసెస్ గుర్తించబడ్డాయి. మీ ముఖం పూర్తిగా కనిపించాలి."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ముఖం కవర్ చేయబడింది. మీ ముఖం పూర్తిగా కనిపించాలి."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ముఖం ధృవీకరించలేరు. హార్డ్‌వేర్ అందుబాటులో లేదు."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8af100d457b1..70d5bb02eea9 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"ปลดล็อกด้วยลายนิ้วมือ"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"ใช้เซ็นเซอร์ลายนิ้วมือไม่ได้"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"โปรดติดต่อผู้ให้บริการซ่อม"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"บันทึกข้อมูลใบหน้าที่ถูกต้องไม่ได้ ลองอีกครั้ง"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"สร้างรูปแบบใบหน้าไม่ได้ โปรดลองอีกครั้ง"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"สว่างเกินไป ลองหาตำแหน่งที่แสงน้อยกว่านี้"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"มืดเกินไป ลองหาตำแหน่งที่สว่างขึ้น"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"เลื่อนโทรศัพท์ออกไปไกลกว่านี้"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"เลื่อนโทรศัพท์เข้าไปใกล้กว่านี้"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"ยกโทรศัพท์ให้สูงขึ้น"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"ถือโทรศัพท์ให้ต่ำลง"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"เลื่อนโทรศัพท์ไปทางซ้าย"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"เลื่อนโทรศัพท์ไปทางขวา"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"ลองหาตำแหน่งที่สว่างขึ้น"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"ถือโทรศัพท์ให้ห่างกว่านี้"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"ถือโทรศัพท์ให้ใกล้กว่านี้"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"ยกโทรศัพท์ให้สูงขึ้น"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"ถือโทรศัพท์ให้ต่ำลง"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"เลื่อนโทรศัพท์ไปทางซ้าย"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"เลื่อนโทรศัพท์ไปทางขวา"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"โปรดมองตรงมาที่อุปกรณ์"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"หันหน้าให้ตรงกับโทรศัพท์"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ไม่เห็นใบหน้า ถือโทรศัพท์ไว้ที่ระดับสายตา"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"มีการเคลื่อนไหวมากเกินไป ถือโทรศัพท์นิ่งๆ"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"โปรดลงทะเบียนใบหน้าอีกครั้ง"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"ใกล้เคียงเกินไป โปรดเปลี่ยนท่าโพส"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"จัดตำแหน่งศีรษะให้ตรง"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ปรับมุมศีรษะให้ตรง"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"จัดตำแหน่งศีรษะให้ตรง"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"ไม่รู้จักใบหน้า โปรดลองอีกครั้ง"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"เปลี่ยนตำแหน่งของศีรษะเล็กน้อย"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"โปรดมองตรงไปที่โทรศัพท์"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"โปรดมองตรงไปที่โทรศัพท์"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"โปรดมองตรงไปที่โทรศัพท์"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"เอาสิ่งที่ปิดบังใบหน้าออก"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ทำความสะอาดด้านบนของหน้าจอ รวมถึงแถบสีดำ"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"ต้องมองเห็นใบหน้าของคุณทั้งหมด"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"ต้องมองเห็นใบหน้าของคุณทั้งหมด"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"สร้างรูปแบบใบหน้าไม่ได้ โปรดลองอีกครั้ง"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"ตรวจพบแว่นตาดำ ต้องมองเห็นใบหน้าของคุณทั้งหมด"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"ตรวจพบหน้ากากอนามัย ต้องมองเห็นใบหน้าของคุณทั้งหมด"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ยืนยันใบหน้าไม่ได้ ฮาร์ดแวร์ไม่พร้อมใช้งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 17085e72f30c..0383ae673253 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Pag-unlock Gamit ang Fingerprint"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Hindi magamit ang sensor para sa fingerprint"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bumisita sa provider ng pag-aayos."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Hindi makakuha ng tamang face data. Subukang muli."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Hindi magawa ang iyong face model. Subukan ulit."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Masyadong maliwanag. Subukang bawasan ang liwanag."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Masyadong madilim. Subukan sa mas maliwanag."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Ilayo pa ang telepono."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Ilapit pa ang telepono."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Itaas pa ang telepono."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Ibaba pa ang telepono."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Igalaw ang telepono pakaliwa."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Igalaw ang telepono pakanan."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Subukan sa mas maliwanag"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Ilayo pa ang telepono"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Ilapit pa ang telepono"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Itaas pa ang telepono"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Ibaba pa ang telepono"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Iusog pakaliwa ang telepono mo"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Iusog pakanan ang telepono mo"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Tumingin nang mas direkta sa iyong device."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Itapat ang mukha mo sa mismong harap ng telepono."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Hindi makita ang mukha mo. Hawakan ang telepono mo nang kapantay ng mata."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Masyadong magalaw. Hawakang mabuti ang telepono."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Paki-enroll muli ang iyong mukha."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Hindi na makilala ang mukha. Subukang muli."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Masyadong magkatulad, pakibago ang pose mo."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Huwag masyadong lumingon."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Bawasan ang pag-tilt ng iyong ulo."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Huwag masyadong lumingon."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Hindi makilala ang mukha. Subukan ulit."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Bahagyang baguhin ang posisyon ng iyong ulo"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Tumingin nang mas direkta sa iyong telepono"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Tumingin nang mas direkta sa iyong telepono"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Tumingin nang mas direkta sa iyong telepono"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alisin ang anumang humaharang sa iyong mukha."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Linisin ang itaas ng iyong screen, kasama ang itim na bar"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Dapat ganap na nakikita ang iyong mukha"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Dapat ganap na nakikita ang iyong mukha"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Hindi magawa ang iyong face model. Subukan ulit."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"May na-detect na madilim na salamin. Dapat ganap na nakikita ang iyong mukha."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"May na-detect na pantakip sa mukha. Dapat ganap na nakikita ang iyong mukha."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Di ma-verify ang mukha. Di available ang hardware."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0bee062367f4..c67d8fbb82ba 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Parmak İzi Kilidi"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Parmak izi sensörü kullanılamıyor"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bir onarım hizmeti sağlayıcıyı ziyaret edin."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Doğru yüz verileri yakalanamadı. Tekrar deneyin."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Yüzünüzün modeli oluşturulamıyor. Tekrar deneyin."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Çok parlak. Parlaklığı daha az bir ışıklandırma deneyin."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Çok karanlık. Daha parlak ışıkta deneyin."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Telefonu uzaklaştırın."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Telefonu yaklaştırın."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Telefonu yukarı kaldırın."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Telefonu aşağı indirin."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Telefonu sola hareket ettirin."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Telefonu sağa hareket ettirin."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Daha parlak ışıkta deneyin"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaklaştırın"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaklaştırın"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu daha yukarı kaldırın"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Telefonu daha aşağı indirin"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Telefonu solunuza kaydırın"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Telefonu sağınıza kaydırın"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Lütfen cihazınıza daha doğrudan bakın."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Yüzünüz telefonun tam karşısına gelmelidir."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Yüzünüz görünmüyor. Telefonunuzu göz hizasında tutun."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Çok fazla hareket ediyorsunuz. Telefonu sabit tutun."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Lütfen yüzünüzü yeniden kaydedin."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Duruşunuz çok benzer, lütfen pozunuzu değiştirin."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı biraz daha az çevirin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Başınızı biraz daha az eğin."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı biraz daha az çevirin."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Yüz tanınamadı. Tekrar deneyin."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Başınızın konumunu hafifçe değiştirin"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonunuza daha doğrudan bakın"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonunuza daha doğrudan bakın"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Telefonunuza daha doğrudan bakın"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Yüzünüzün görünmesini engelleyen şeyleri kaldırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Siyah çubuk da dahil olmak üzere ekranınızın üst kısmını temizleyin"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Yüzünüz tamamen görünür olmalıdır"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Yüzünüz tamamen görünür olmalıdır"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Yüzünüzün modeli oluşturulamıyor. Tekrar deneyin."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Koyu renk gözlükler algılandı. Yüzünüz tamamen görünür olmalıdır."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Yüzünüzü kapattığınız algılandı. Yüzünüz tamamen görünür olmalıdır."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Yüz doğrulanamıyor. Donanım kullanılamıyor."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d69e256e9470..547b471babc3 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -636,26 +636,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Розблокування відбитком пальця"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Не вдається скористатися сканером відбитків пальців"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Зверніться до постачальника послуг із ремонту."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Не вдалося чітко зняти обличчя. Повторіть спробу."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Модель обличчя не створено. Повторіть спробу."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадто яскраво. Потрібно менше світла."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Занадто темно. Потрібно більше світла."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Тримайте телефон далі від обличчя."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Тримайте телефон ближче до обличчя."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Тримайте телефон вище."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Тримайте телефон нижче."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Тримайте телефон лівіше."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Тримайте телефон правіше."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Потрібно більше світла"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Тримайте телефон далі від обличчя"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Тримайте телефон ближче до обличчя"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Підніміть телефон вище"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Опустіть телефон нижче"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Тримайте телефон лівіше"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Тримайте телефон правіше"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Дивіться просто на пристрій."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Тримайте телефон просто перед обличчям."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Обличчя не видно. Утримуйте телефон на рівні очей."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Забагато рухів. Тримайте телефон нерухомо."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторно проскануйте обличчя."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Надто схоже на попередню спробу, змініть позу."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Трохи перемістіть обличчя."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Трохи зменште нахил голови."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Трохи поверніть обличчя."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Обличчя не розпізнано. Повторіть спробу."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Трохи змініть положення голови"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Дивіться на телефон прямо"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Дивіться на телефон прямо"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Дивіться на телефон прямо"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Приберіть об’єкти, які затуляють ваше обличчя."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистьте верхню частину екрана, зокрема чорну панель"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Обличчя має бути видно повністю"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Обличчя має бути видно повністю"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Не вдається створити модель обличчя. Повторіть спробу."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Виявлено темні окуляри. Обличчя має бути видно повністю."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Виявлено аксесуар, який закриває обличчя. Обличчя має бути видно повністю."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Не вдається перевірити обличчя. Апаратне забезпечення недоступне."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7e170af78b2f..54f0e0e16795 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"فنگر پرنٹ اَن لاک"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"فنگر پرنٹ سینسر کا استعمال نہیں کر سکتے"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ایک مرمت فراہم کنندہ کو ملاحظہ کریں۔"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"چہرے کا درست ڈيٹا کیپچر نہیں ہو سکا۔ پھر آزمائيں۔"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"آپ کے چہرے کا ماڈل تخلیق نہیں کیا جا سکتا۔ پھر کوشش کریں۔"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"کافی روشنی ہے۔ ہلکی روشنی میں آزمائیں۔"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"کافی اندھیرا ہے۔ تیز روشنی میں آزمائیں۔"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"فون کو تھوڑا دور کریں۔"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"فون کو تھوڑا قریب کریں۔"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"فون کو تھوڑا اوپر لے جائیں۔"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"فون تھوڑا نیچے کریں۔"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"فون کو بائیں جانب لے جائيں۔"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"فون کو دائیں جانب لے جائیں۔"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"تیز روشنی میں آزمائیں"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"فون کو تھوڑا دور کریں"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"فون کو تھوڑا قریب کریں"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"فون کو تھوڑا اوپر لے جائیں"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"فون تھوڑا نیچے کریں"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"فون کو اپنی بائیں جانب لے جائیں"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"فون کو اپنی دائیں جانب لے جائیں"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"براہ کرم اپنے آلہ کی طرف چہرے کو سیدھا رکھیں۔"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"اپنے چہرے کو براہ راست فون کے سامنے رکھیں۔"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"آپ کا چہرہ دکھائی نہیں دے رہا۔ اپنے فون کو آنکھ کی سطح پر پکڑیں۔"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"کافی حرکت ہو رہی ہے۔ فون کو مضبوطی سے پکڑیں۔"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"براہ کرم اپنے چہرے کو دوبارہ مندرج کریں۔"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"کافی ملتا جلتا ہے، براہ کرم اپنا پوز بدلیں۔"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"اپنا سر تھوڑا کم کریں۔"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"اپنا سر تھوڑا کم جھکائیں۔"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"اپنا سر تھوڑا کم کریں۔"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"چہرے کی شناخت نہیں ہو سکی۔ پھر کوشش کریں۔"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"اپنے سر کی پوزیشن کو تھوڑا تبدیل کریں"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"اپنے فون کی طرف چہرے کو سیدھا رکھیں"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"اپنے فون کی طرف چہرے کو سیدھا رکھیں"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"اپنے فون کی طرف چہرے کو سیدھا رکھیں"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"آپ کے چہرہ کو چھپانے والی ہر چیز کو ہٹائیں۔"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"سیاہ بار سمیت، اپنی اسکرین کے اوپری حصے کو صاف کریں"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"آپ کا چہرہ مکمل طور پر دکھائی دینا ضروری ہے"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"آپ کا چہرہ مکمل طور پر دکھائی دینا ضروری ہے"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"آپ کے چہرے کا ماڈل تخلیق نہیں کیا جا سکتا۔ پھر کوشش کریں۔"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"گہرے چشمے کا پتہ چلا۔ آپ کا چہرہ مکمل طور پر دکھائی دینا ضروری ہے۔"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"چہرے کو ڈھانپنے کا پتہ چلا۔ آپ کا چہرہ مکمل طور پر دکھائی دینا ضروری ہے۔"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چہرے کی توثیق نہیں کی جا سکی۔ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index f8703604d37e..e920bdac5134 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Barmoq izi bilan ochish"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Barmoq izi skaneridan foydalanish imkonsiz"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Xizmat koʻrsatish markaziga murojaat qiling."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Yuz ravshan suratga olinmadi. Qaytadan urining."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Yuzingiz modeli yaratilmadi. Qayta urining."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Juda yorqin. Biroz soyaroq joy tanlang."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Juda qorongʻi. Atrofingizni yoriting."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Telefonni biroz uzoqroq tuting."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Telefonni yaqinroq tuting."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Telefonni teparoq tuting."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Telefonni pastroq tushiring."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Telefonni chapga suring."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Telefonni oʻngga suring."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Atrofingizni yoriting"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonni biroz uzoqroq tuting"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonni yaqinroq tuting"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonni teparoq tuting"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Telefonni pastroq tuting"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Telefonni chaproq tuting"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Telefonni oʻngroq tuting"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Qurilmaga tik qarang."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Telefonni yuzingizga tik qarating."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Yuzingiz koʻrinmayapti. Telefonni koʻz balandligida tuting."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ortiqcha harakatlanmoqda. Qimirlatmasdan ushlang."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Yuzingizni qaytadan qayd qildiring."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Yuz tanilmadi. Qaytadan urining."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Yuz ifodasi oldingiday. Holatingizni oʻzgartiring."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Boshingizni asta buring."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Boshingizni asta qiyalang."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Boshingizni asta buring."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Yuz aniqlanmadi. Qayta urining."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Boshingiz holatini biroz oʻzgartiring"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonga tik qarab turing"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonga tik qarab turing"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Telefonga tik qarab turing"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Yuzingizni berkitayotgan narsalarni olib tashlang."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ekranning yuqori qismini, shuningdek, qora panelni ham tozalang"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Yuzingiz toʻliq koʻrinishi kerak"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Yuzingiz toʻliq koʻrinishi kerak"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Yuzingiz modeli yaratilmadi. Qayta urining."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Qora koʻzoynak aniqlandi. Yuzingiz toʻliq koʻrinishi kerak."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Yuzning bir qismi yopilib qolgan. Yuzingiz toʻliq koʻrinishi kerak."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Yuzingiz tasdiqlanmadi. Qurilma ishlamayapti."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ce47bc509826..6ca2979871a1 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Mở khóa bằng vân tay"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Không thể dùng cảm biến vân tay"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Hãy liên hệ với một nhà cung cấp dịch vụ sửa chữa."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Không thể ghi lại đúng dữ liệu mặt. Hãy thử lại."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Không thể tạo mẫu khuôn mặt của bạn. Hãy thử lại."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Quá sáng. Hãy thử giảm độ sáng."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Quá tối. Hãy thử tăng độ sáng."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Đưa điện thoại ra xa hơn."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Đưa điện thoại lại gần hơn."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Nâng điện thoại lên cao hơn."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Hạ thấp điện thoại xuống."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Đưa điện thoại sang bên trái."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Đưa điện thoại sang bên phải."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Hãy thử tăng độ sáng"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Đưa điện thoại ra xa hơn"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Đưa điện thoại lại gần hơn"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Nâng điện thoại lên cao hơn"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Hạ thấp điện thoại xuống"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Đưa điện thoại sang bên trái"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Đưa điện thoại sang bên phải"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Vui lòng nhìn thẳng vào thiết bị."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Hướng thẳng khuôn mặt về phía trước điện thoại."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Không thấy khuôn mặt bạn. Cầm điện thoại ngang tầm mắt"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Thiết bị di chuyển quá nhiều. Giữ yên thiết bị."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vui lòng đăng ký lại khuôn mặt của bạn."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Khuôn mặt quá giống nhau, vui lòng đổi tư thế."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Hãy bớt di chuyển đầu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Hãy bớt ngửa hoặc cúi đầu."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Hãy bớt di chuyển đầu."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Không thể nhận dạng khuôn mặt. Hãy thử lại."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nghiêng đầu của bạn một chút"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Nhìn thẳng vào điện thoại"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Nhìn thẳng vào điện thoại"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Nhìn thẳng vào điện thoại"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hãy loại bỏ mọi thứ che khuất khuôn mặt bạn."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vệ sinh phần đầu màn hình, bao gồm cả thanh màu đen"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Toàn bộ khuôn mặt của bạn phải được hiển thị"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Toàn bộ khuôn mặt của bạn phải được hiển thị"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Không thể tạo mẫu khuôn mặt của bạn. Hãy thử lại."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Đã phát hiện đeo kính đen. Toàn bộ khuôn mặt của bạn phải được hiển thị."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Đã phát hiện khuôn mặt bị che khuất. Toàn bộ khuôn mặt của bạn phải được hiển thị."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Không thể xác minh khuôn mặt. Phần cứng không có sẵn."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4fa44fbcd040..a3fd21ba3733 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"指纹解锁"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"无法使用指纹传感器"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"请联系维修服务提供商。"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"无法捕获准确的人脸数据,请重试。"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"无法创建您的脸部模型,请重试。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度过高,请尝试使用较柔和的亮度。"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"亮度不足,请尝试将光线调亮。"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"请将手机拿远一点。"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"请将手机拿近一点。"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"请将手机举高一点。"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"请将手机拿低一点。"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"请将手机向左移动。"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"请将手机向右移动。"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"请尝试调亮光线"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"请将手机拿远一点"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"请将手机拿近一点"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"请将手机举高一点"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"请将手机拿低一点"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"请将手机向左移动"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"请将手机向右移动"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"请直视您的设备。"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"请将你的面部正对手机。"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"看不清您的脸部,请将手机举到与眼睛齐平的位置。"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"摄像头过于晃动。请将手机拿稳。"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"请重新注册您的面孔。"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"已无法识别人脸,请重试。"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"与先前的姿势太相近,请换一个姿势。"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"请将您的头稍微上下倾斜。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"请稍微抬头或低头。"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"请将您的头稍微左右旋转。"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"无法识别人脸,请重试。"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"请略微更改头部的位置"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"请尽量直视手机"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"请尽量直视手机"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"请尽量直视手机"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"请移除所有遮挡您面部的物体。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"请将屏幕顶部(包括黑色条栏)清理干净"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"您的脸部必须完全可见"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"您的脸部必须完全可见"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"无法创建您的脸部模型,请重试。"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"检测到墨镜,您的脸部必须完全可见。"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"检测到脸部有遮挡物,您的脸部必须完全可见。"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"无法验证人脸。硬件无法使用。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 7198d4e41e2a..589a7603aac9 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"指紋解鎖"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"無法使用指紋感應器"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請諮詢維修服務供應商。"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"無法擷取準確的臉容資料。請再試一次。"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立面部模型,請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"影像太亮。請嘗試在更暗的環境下使用。"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"影像太暗。請嘗試在更明亮的環境下使用。"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"請將手機移遠一點。"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"請將手機移近一點。"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"請將手機向上移。"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"請將手機向下移。"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"請將手機向左移。"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"請將手機向右移。"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"請嘗試在更明亮的環境下使用"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機移遠一點"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機移近一點"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機向上移"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"請將手機向下移"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"請將手機向左移"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"請將手機向右移"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"請以更直視的角度看著裝置。"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"將手機對準您的臉孔正面。"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"看不到您的臉。將手機保持與視線同高。"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"裝置不夠穩定。請拿穩手機。"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊臉孔。"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"無法再識別臉孔。請再試一次。"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"臉孔位置太相近,請改變您的姿勢。"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"減少頭部左右轉動幅度。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"減少頭部傾斜幅度。"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"減少頭部左右轉動幅度。"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"無法辨識面孔,請再試一次。"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"請稍微變更頭部的位置"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"盡可能直視手機"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"盡可能直視手機"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"盡可能直視手機"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"移除遮住您臉孔的任何東西。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂部,包括黑色列"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"您必須展示整個面孔。"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"您必須展示整個面孔。"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"無法建立面部模型,請再試一次。"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"偵測到深色眼鏡。您必須展示整個面孔。"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"偵測到面部遮蓋物。您必須展示整個面孔。"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"無法驗證臉孔,硬件無法使用。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e0a06d5e15bc..dd84bd11a466 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"指紋解鎖"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"指紋感應器無法使用"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請洽詢維修供應商。"</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"無法擷取精準臉孔資料,請再試一次。"</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立臉部模型,請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度過高,請嘗試使用較柔和的照明方式。"</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"亮度不足,請嘗試使用較明亮的照明方式。"</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"請將手機拿遠一點。"</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"請將手機拿近一點。"</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"請將手機舉高一點。"</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"請將手機拿低一點。"</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"請將手機向左移動。"</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"請將手機向右移動。"</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"請試著提高亮度"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機拿遠一點"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機拿近一點"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機舉高一點"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"請將手機拿低一點"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"請將手機向左移"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"請將手機向右移"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"請儘可能直視裝置正面。"</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"將你的臉孔正對手機。"</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"未偵測到你的臉,請將手機舉到與視線同高。"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"鏡頭過度晃動,請拿穩手機。"</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊你的臉孔。"</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"已無法辨識臉孔,請再試一次。"</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"與先前的姿勢太相似,請換一個姿勢。"</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"請將你的頭部稍微向左或向右轉動。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"請稍微抬頭或低頭。"</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"請將你的頭部稍微向左或向右旋轉。"</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"無法辨識這張臉,請再試一次。"</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"請稍微改變頭部位置"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"請盡可能直視手機"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"請盡可能直視手機"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"請盡可能直視手機"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"請移除任何會遮住臉孔的物體。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂端,包括黑色橫列"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"請露出整張臉"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"請露出整張臉"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"無法建立臉部模型,請再試一次。"</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"偵測到墨鏡,請露出整張臉。"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"偵測到有物品遮住臉,請露出整張臉。"</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"相關硬體無法使用,因此無法驗證臉孔。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8f3be13e2867..7c930cc7410f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -634,26 +634,31 @@
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Ukuvula ngesigxivizo somunwe"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Ayikwazi ukusebenzisa inzwa yesigxivizo somunwe"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vakashela umhlinzeki wokulungisa."</string>
- <string name="face_acquired_insufficient" msgid="2150805835949162453">"Ayikwazanga ukuthwebula idatha enembile yobuso. Zama futhi."</string>
+ <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ayikwazi ukusungula imodeli yobuso bakho. Zama futhi."</string>
<string name="face_acquired_too_bright" msgid="8070756048978079164">"Kukhanya kakhulu. Zama ukukhanya okuthambile."</string>
- <string name="face_acquired_too_dark" msgid="252573548464426546">"Kumnyama kakhulu Zama ukukhanyisa okukhanyayo."</string>
- <string name="face_acquired_too_close" msgid="1628767882971469833">"Hambisa ifoni kude."</string>
- <string name="face_acquired_too_far" msgid="5098567726427173896">"Sondeza ifoni eduze."</string>
- <string name="face_acquired_too_high" msgid="4868033653626081839">"Hambisa ifoni phezulu."</string>
- <string name="face_acquired_too_low" msgid="1512237819632165945">"Hambisa ifoni ngaphansi."</string>
- <string name="face_acquired_too_right" msgid="2513391513020932655">"Hambisa ifoni ngakwesokunxele."</string>
- <string name="face_acquired_too_left" msgid="8882499346502714350">"Hambisa ifoni ngakwesokudla."</string>
+ <string name="face_acquired_too_dark" msgid="7919016380747701228">"Zama ukukhanyisa okukhanyayo"</string>
+ <string name="face_acquired_too_close" msgid="4453646176196302462">"Yisa ifoni kude"</string>
+ <string name="face_acquired_too_far" msgid="2922278214231064859">"Sondeza ifoni eduze"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Yisa ifoni phezulu"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Yisa ifoni phansi"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"Yisa ifoni ngakwesokunxele sakho"</string>
+ <string name="face_acquired_too_left" msgid="9201762240918405486">"Yisa ifoni ngakwesokudla sakho"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Sicela ubheke ngokuqondile kakhulu kudivayisi yakho."</string>
- <string name="face_acquired_not_detected" msgid="2945945257956443257">"Beka ubuso bakho ngqo phambi kwefoni."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ayikwazi ukubona ubuso bakho. Bamba ifoni yakho iqondane namehlo"</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ukunyakaza okuningi kakhulu. Bamba ifoni iqine."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Sicela uphinde ubhalise ubuso bakho."</string>
- <string name="face_acquired_too_different" msgid="4699657338753282542">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
- <string name="face_acquired_too_similar" msgid="7684650785108399370">"Kufana kakhulu, sicela ushintshe ukuma kwakho."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Jikisa ikhanda lakho kancane."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tshekisa kancane ikhanda lakho."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Jikisa ikhanda lakho kancane."</string>
+ <string name="face_acquired_too_different" msgid="2520389515612972889">"Ayikwazi ukubona ubuso. Zama futhi."</string>
+ <string name="face_acquired_too_similar" msgid="8882920552674125694">"Shintsha indawo yekhanda lakho kancane"</string>
+ <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Bheka ngqo kakhulu kufoni yakho"</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Bheka ngqo kakhulu kufoni yakho"</string>
+ <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Bheka ngqo kakhulu kufoni yakho"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Susa noma yini efihle ubuso bakho."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hlanza okuphezulu kwesikrini sakho, kufaka phakathi ibha emnyama"</string>
+ <string name="face_acquired_dark_glasses_detected" msgid="7263638432128692048">"Ubuso bakho kufanele bubonakale ngokugcwele"</string>
+ <string name="face_acquired_mouth_covering_detected" msgid="615991670821926847">"Ubuso bakho kufanele bubonakale ngokugcwele"</string>
+ <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Ayikwazi ukusungula imodeli yobuso bakho. Zama futhi."</string>
+ <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Kutholwe izibuko ezimnyama. Ubuso bakho kufanele bubonakale ngokugcwele."</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Kutholwe ukumbozwa kobuso. Ubuso bakho kufanele bubonakale ngokugcwele."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ayikwazi ukuqinisekisa ubuso. Izingxenyekazi zekhompyutha azitholakali."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d2f31b05313d..08471c3429e3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2422,6 +2422,15 @@
<!-- When closing the current activity, this is the animation that is
run on the current activity (which is exiting the screen). -->
<attr name="activityCloseExitAnimation" format="reference" />
+ <!-- When closing a dream activity, this is the animation that is
+ run on the dream activity (which is exiting the screen). -->
+ <attr name="dreamActivityCloseExitAnimation" format="reference" />
+ <!-- When opening a dream activity, this is the animation that is
+ run on the dream activity (which is entering the screen). -->
+ <attr name="dreamActivityOpenEnterAnimation" format="reference" />
+ <!-- When opening a dream activity, this is the animation that is
+ run on the old activity (which is exiting the screen). -->
+ <attr name="dreamActivityOpenExitAnimation" format="reference" />
<!-- When opening an activity in a new task, this is the animation that is
run on the activity of the new task (which is entering the screen). -->
<attr name="taskOpenEnterAnimation" format="reference" />
@@ -3376,6 +3385,50 @@
<p>This is true by default.
See {@link android.view.View#setAutoHandwritingEnabled}. -->
<attr name="autoHandwritingEnabled" format="boolean" />
+
+ <!-- <p>The amount of offset that is applied to the left edge of the view's stylus
+ handwriting bounds, which by default is the view's visible bounds.
+
+ <p>This attribute is mainly used to enlarge the view's handwriting bounds for better
+ user experience. Note that a positive offset means the bounds is extended outwards,
+ and vice versa. See {@link android.view.View#setHandwritingBoundsOffsets}
+
+ <p> The default value is 10dp for {@link android.widget.TextView} and
+ {@link android.widget.EditText}, and 0dp for other views. -->
+ <attr name="handwritingBoundsOffsetLeft" format="dimension" />
+
+ <!-- <p>The amount of offset that is applied to the top edge of the view's stylus
+ handwriting bounds, which by default is the view's visible bounds.
+
+ <p>This attribute is mainly used to enlarge the view's handwriting bounds for better
+ user experience. Note that a positive offset means the bounds is extended outwards,
+ and vice versa. See {@link android.view.View#setHandwritingBoundsOffsets}
+
+ <p> The default value is 40dp for {@link android.widget.TextView} and
+ {@link android.widget.EditText}, and 0dp for other views. -->
+ <attr name="handwritingBoundsOffsetTop" format="dimension" />
+
+ <!-- <p>The amount of offset that is applied to the right edge of the view's stylus
+ handwriting bounds, which by default is the view's visible bounds.
+
+ <p>This attribute is mainly used to enlarge the view's handwriting bounds for better
+ user experience. Note that a positive offset means the bounds is extended outwards,
+ and vice versa. See {@link android.view.View#setHandwritingBoundsOffsets}
+
+ <p> The default value is 10dp for {@link android.widget.TextView} and
+ {@link android.widget.EditText}, and 0dp for other views. -->
+ <attr name="handwritingBoundsOffsetRight" format="dimension" />
+
+ <!-- <p>The amount of offset that is applied to the bottom edge of the view's stylus
+ handwriting bounds, which by default is the view's visible bounds.
+
+ <p>This attribute is mainly used to enlarge the view's handwriting bounds for better
+ user experience. Note that a positive offset means the bounds is extended outwards,
+ and vice versa. See {@link android.view.View#setHandwritingBoundsOffsets}
+
+ <p> The default value is 40dp for {@link android.widget.TextView} and
+ {@link android.widget.EditText}, and 0dp for all other views. -->
+ <attr name="handwritingBoundsOffsetBottom" format="dimension" />
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7562b9aa0ead..0acf7031e407 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2084,6 +2084,11 @@
<attr name="protectionLevel" />
<attr name="permissionFlags" />
<attr name="knownCerts" />
+ <!-- Optional: specify the maximum version of the Android OS for which the
+ application wishes to create the permission. When running on a version
+ of Android higher than the number given here, the permission will not
+ be created. -->
+ <attr name="maxSdkVersion" />
</declare-styleable>
<!-- The <code>permission-group</code> tag declares a logical grouping of
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 54c3490740e5..74f78d2618a7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2577,6 +2577,10 @@
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+ <!-- Base "handwriting slop" value used by ViewConfiguration as a
+ movement threshold where stylus handwriting should begin. -->
+ <dimen name="config_viewConfigurationHandwritingSlop">4dp</dimen>
+
<!-- Base "hover slop" value used by ViewConfiguration as a
movement threshold under which hover is considered "stationary". -->
<dimen name="config_viewConfigurationHoverSlop">4dp</dimen>
@@ -3755,6 +3759,9 @@
"Guest" and "Reset guest". -->
<bool name="config_guestUserAutoCreated">false</bool>
+ <!-- If true, owner can change guest user ephemeral state via UI option -->
+ <bool name="config_guestUserAllowEphemeralStateChange">true</bool>
+
<!-- Enforce strong auth on boot. Setting this to false represents a security risk and should
not be ordinarily done. The only case in which this might be permissible is in a car head
unit where there are hardware mechanisms to protect the device (physical keys) and not
@@ -5133,16 +5140,24 @@
-->
<color name="config_letterboxBackgroundColor">@android:color/system_neutral2_900</color>
- <!-- Horizonal position of a center of the letterboxed app window.
+ <!-- Horizontal position of a center of the letterboxed app window.
0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
- or > 1, it is ignored and central positionis used (0.5). -->
+ or > 1, it is ignored and central position is used (0.5). -->
<item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>
- <!-- Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- device orientation. -->
- <bool name="config_letterboxIsReachabilityEnabled">false</bool>
+ <!-- Vertical position of a center of the letterboxed app window.
+ 0 corresponds to the upper side of the screen and 1 to the lower side. If given value < 0
+ or > 1, it is ignored and central position is used (0.5). -->
+ <item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.5</item>
+
+ <!-- Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps.
+ -->
+ <bool name="config_letterboxIsHorizontalReachabilityEnabled">false</bool>
+
+ <!-- Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps. -->
+ <bool name="config_letterboxIsVerticalReachabilityEnabled">false</bool>
- <!-- Default horizonal position of the letterboxed app window when reachability is
+ <!-- Default horizontal position of the letterboxed app window when reachability is
enabled and an app is fullscreen in landscape device orientation. When reachability is
enabled, the position can change between left, center and right. This config defines the
default one:
@@ -5150,11 +5165,30 @@
- Option 1 - Center.
- Option 2 - Right.
If given value is outside of this range, the option 1 (center) is assummed. -->
- <integer name="config_letterboxDefaultPositionForReachability">1</integer>
+ <integer name="config_letterboxDefaultPositionForHorizontalReachability">1</integer>
+
+ <!-- Default vertical position of the letterboxed app window when reachability is
+ enabled and an app is fullscreen in portrait device orientation. When reachability is
+ enabled, the position can change between top, center and bottom. This config defines the
+ default one:
+ - Option 0 - Top.
+ - Option 1 - Center.
+ - Option 2 - Bottom.
+ If given value is outside of this range, the option 1 (center) is assummed. -->
+ <integer name="config_letterboxDefaultPositionForVerticalReachability">1</integer>
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>
+ <!-- Default min aspect ratio for unresizable apps which is used when an app doesn't specify
+ android:minAspectRatio in accordance with CDD 7.1.1.2 requirement:
+ https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio.
+ An exception will be thrown if the given aspect ratio < 4:3. -->
+ <item name="config_letterboxDefaultMinAspectRatioForUnresizableApps" format="float" type="dimen">1.5</item>
+
+ <!-- Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. -->
+ <bool name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled">false</bool>
+
<!-- Whether a camera compat controller is enabled to allow the user to apply or revert
treatment for stretched issues in camera viewfinder. -->
<bool name="config_isCameraCompatControlForStretchedIssuesEnabled">false</bool>
@@ -5813,4 +5847,7 @@
<string-array name="config_serviceStateLocationAllowedPackages">
<item>"com.android.phone"</item>
</string-array>
+
+ <!-- Whether the wake screen on notifications feature is available. -->
+ <bool name="config_pulseOnNotificationsAvailable">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bb36ededc581..09571213e81f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -1010,4 +1010,10 @@
<!-- Dimensions for the translations of the default dialog animation. -->
<dimen name="popup_enter_animation_from_y_delta">20dp</dimen>
<dimen name="popup_exit_animation_to_y_delta">-10dp</dimen>
+
+ <!-- Default handwriting bounds offsets for editors. -->
+ <dimen name="handwriting_bounds_offset_left">10dp</dimen>
+ <dimen name="handwriting_bounds_offset_top">40dp</dimen>
+ <dimen name="handwriting_bounds_offset_right">10dp</dimen>
+ <dimen name="handwriting_bounds_offset_bottom">40dp</dimen>
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index f09ffbe4466b..edebc7a8b604 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -110,6 +110,10 @@
<eat-comment/>
<staging-public-group type="attr" first-id="0x01ce0000">
+ <public name="handwritingBoundsOffsetLeft" />
+ <public name="handwritingBoundsOffsetTop" />
+ <public name="handwritingBoundsOffsetRight" />
+ <public name="handwritingBoundsOffsetBottom" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01cd0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e5d90f00f327..c6b60f586047 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1798,45 +1798,57 @@
<string name="fingerprint_recalibrate_notification_content">Visit a repair provider.</string>
<!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
- <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string>
+ <string name="face_acquired_insufficient">Can\u2019t create your face model. Try again.</string>
<!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
<string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
<!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
- <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string>
+ <string name="face_acquired_too_dark">Try brighter lighting</string>
<!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_close">Move phone farther away.</string>
+ <string name="face_acquired_too_close">Move phone farther away</string>
<!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_far">Move phone closer.</string>
+ <string name="face_acquired_too_far">Move phone closer</string>
<!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_high">Move phone higher.</string>
+ <string name="face_acquired_too_high">Move phone higher</string>
<!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_low">Move phone lower.</string>
+ <string name="face_acquired_too_low">Move phone lower</string>
<!-- Message shown during face acquisition when only the right part of the user's face was detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_right">Move phone to the left.</string>
+ <string name="face_acquired_too_right">Move phone to your left</string>
<!-- Message shown during face acquisition when only the left part of the user's face was detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_left">Move phone to the right.</string>
+ <string name="face_acquired_too_left">Move phone to your right</string>
<!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
<string name="face_acquired_poor_gaze">Please look more directly at your device.</string>
- <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
- <string name="face_acquired_not_detected">Position your face directly in front of the phone.</string>
+ <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=75] -->
+ <string name="face_acquired_not_detected">Can\u2019t see your face. Hold your phone at eye level.</string>
<!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
<string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
<!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
<string name="face_acquired_recalibrate">Please re-enroll your face.</string>
<!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string>
+ <string name="face_acquired_too_different">Can\u2019t recognize face. Try again.</string>
<!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
- <string name="face_acquired_too_similar">Too similar, please change your pose.</string>
+ <string name="face_acquired_too_similar">Change the position of your head slightly</string>
<!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
- <string name="face_acquired_pan_too_extreme">Turn your head a little less.</string>
+ <string name="face_acquired_pan_too_extreme">Look more directly at your phone</string>
<!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
- <string name="face_acquired_tilt_too_extreme">Tilt your head a little less.</string>
+ <string name="face_acquired_tilt_too_extreme">Look more directly at your phone</string>
<!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
- <string name="face_acquired_roll_too_extreme">Turn your head a little less.</string>
+ <string name="face_acquired_roll_too_extreme">Look more directly at your phone</string>
<!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
<string name="face_acquired_obscured">Remove anything hiding your face.</string>
<!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=100] -->
<string name="face_acquired_sensor_dirty">Clean the top of your screen, including the black bar</string>
+ <!-- Message shown during acquisition when dark glasses were detected [CHAR LIMIT=75] -->
+ <string name="face_acquired_dark_glasses_detected">Your face must be fully visible</string>
+ <!-- Message shown during acquisition when a mouth covering was detected [CHAR LIMIT=75] -->
+ <string name="face_acquired_mouth_covering_detected">Your face must be fully visible</string>
+
+ <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=75] -->
+ <string name="face_acquired_recalibrate_alt">Can\u2019t create your face model. Try again.</string>
+ <!-- Message shown during acquisition when dark glasses were detected [CHAR LIMIT=100] -->
+ <string name="face_acquired_dark_glasses_detected_alt">Dark glasses detected. Your face must be fully visible.</string>
+ <!-- Message shown during acquisition when a mouth covering was detected [CHAR LIMIT=100] -->
+ <string name="face_acquired_mouth_covering_detected_alt">Face covering detected. Your face must be fully visible.</string>
+
<!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_acquired_vendor">
</string-array>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5d17047d7430..2dd563d0b843 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -85,6 +85,9 @@ please see styles_device_defaults.xml.
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
+ <item name="dreamActivityCloseExitAnimation">@anim/dream_activity_close_exit</item>
+ <item name="dreamActivityOpenEnterAnimation">@anim/dream_activity_open_enter</item>
+ <item name="dreamActivityOpenExitAnimation">@anim/dream_activity_open_exit</item>
<item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
<item name="taskOpenExitAnimation">@anim/task_open_exit</item>
<item name="launchTaskBehindTargetAnimation">@anim/launch_task_behind_target</item>
@@ -505,6 +508,10 @@ please see styles_device_defaults.xml.
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
<item name="breakStrategy">high_quality</item>
<item name="hyphenationFrequency">@dimen/config_preferredHyphenationFrequency</item>
+ <item name="handwritingBoundsOffsetLeft">@dimen/handwriting_bounds_offset_left</item>
+ <item name="handwritingBoundsOffsetTop">@dimen/handwriting_bounds_offset_top</item>
+ <item name="handwritingBoundsOffsetRight">@dimen/handwriting_bounds_offset_right</item>
+ <item name="handwritingBoundsOffsetBottom">@dimen/handwriting_bounds_offset_bottom</item>
</style>
<style name="Widget.CheckedTextView">
@@ -540,6 +547,10 @@ please see styles_device_defaults.xml.
<item name="breakStrategy">simple</item>
<item name="hyphenationFrequency">@dimen/config_preferredHyphenationFrequency</item>
<item name="defaultFocusHighlightEnabled">false</item>
+ <item name="handwritingBoundsOffsetLeft">@dimen/handwriting_bounds_offset_left</item>
+ <item name="handwritingBoundsOffsetTop">@dimen/handwriting_bounds_offset_top</item>
+ <item name="handwritingBoundsOffsetRight">@dimen/handwriting_bounds_offset_right</item>
+ <item name="handwritingBoundsOffsetBottom">@dimen/handwriting_bounds_offset_bottom</item>
</style>
<style name="Widget.ExpandableListView" parent="Widget.ListView">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 96e8de0d2d64..45791b8ea6f8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -394,6 +394,7 @@
<java-symbol type="bool" name="config_supportsInsecureLockScreen" />
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="bool" name="config_guestUserAutoCreated" />
+ <java-symbol type="bool" name="config_guestUserAllowEphemeralStateChange" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
<java-symbol type="array" name="config_localPrivateDisplayPorts" />
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
@@ -490,6 +491,7 @@
<java-symbol type="dimen" name="config_minScrollbarTouchTarget" />
<java-symbol type="dimen" name="config_prefDialogWidth" />
<java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
+ <java-symbol type="dimen" name="config_viewConfigurationHandwritingSlop" />
<java-symbol type="dimen" name="config_viewConfigurationHoverSlop" />
<java-symbol type="dimen" name="config_ambiguousGestureMultiplier" />
<java-symbol type="dimen" name="config_viewMinFlingVelocity" />
@@ -1419,6 +1421,9 @@
<java-symbol type="drawable" name="ic_corp_user_badge" />
<java-symbol type="drawable" name="ic_corp_badge_no_background" />
<java-symbol type="drawable" name="ic_corp_statusbar_icon" />
+ <java-symbol type="drawable" name="ic_test_badge_experiment" />
+ <java-symbol type="drawable" name="ic_test_badge_no_background" />
+ <java-symbol type="drawable" name="ic_test_icon_badge_experiment" />
<java-symbol type="drawable" name="ic_instant_icon_badge_bolt" />
<java-symbol type="drawable" name="emulator_circular_window_overlay" />
<java-symbol type="drawable" name="ic_qs_battery_saver" />
@@ -2657,6 +2662,11 @@
<java-symbol type="string" name="face_acquired_roll_too_extreme" />
<java-symbol type="string" name="face_acquired_obscured" />
<java-symbol type="string" name="face_acquired_sensor_dirty" />
+ <java-symbol type="string" name="face_acquired_dark_glasses_detected" />
+ <java-symbol type="string" name="face_acquired_mouth_covering_detected" />
+ <java-symbol type="string" name="face_acquired_recalibrate_alt" />
+ <java-symbol type="string" name="face_acquired_dark_glasses_detected_alt" />
+ <java-symbol type="string" name="face_acquired_mouth_covering_detected_alt" />
<java-symbol type="array" name="face_acquired_vendor" />
<java-symbol type="string" name="face_name_template" />
<java-symbol type="string" name="face_app_setting_name" />
@@ -3331,6 +3341,7 @@
<java-symbol type="string" name="config_dozeTapSensorType" />
<java-symbol type="array" name="config_dozeTapSensorPostureMapping" />
<java-symbol type="bool" name="config_dozePulsePickup" />
+ <java-symbol type="bool" name="config_pulseOnNotificationsAvailable" />
<!-- Used for MimeIconUtils. -->
<java-symbol type="drawable" name="ic_doc_apk" />
@@ -4382,9 +4393,14 @@
<java-symbol type="integer" name="config_letterboxBackgroundType" />
<java-symbol type="color" name="config_letterboxBackgroundColor" />
<java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
- <java-symbol type="bool" name="config_letterboxIsReachabilityEnabled" />
- <java-symbol type="integer" name="config_letterboxDefaultPositionForReachability" />
+ <java-symbol type="dimen" name="config_letterboxVerticalPositionMultiplier" />
+ <java-symbol type="bool" name="config_letterboxIsHorizontalReachabilityEnabled" />
+ <java-symbol type="bool" name="config_letterboxIsVerticalReachabilityEnabled" />
+ <java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
+ <java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
+ <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
+ <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
diff --git a/core/res/res/xml-watch/default_zen_mode_config.xml b/core/res/res/xml-watch/default_zen_mode_config.xml
deleted file mode 100644
index 938cc0c3f7c0..000000000000
--- a/core/res/res/xml-watch/default_zen_mode_config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2016, 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.
--->
-
-<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="2">
- <!-- Allow starred contacts to go through only.
- Repeated calls, calls, messages, reminders, events off. -->
- <allow from="2" repeatCallers="false" calls="false" messages="false" reminders="false"
- events="false"/>
-</zen>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index c88e512286f2..08135e82e7bd 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -156,7 +156,7 @@
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
- <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
+ <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
<!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
<shortcode country="jp" pattern="\\d{1,5}" free="8083" />
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index c112cbb47b55..6f2366e32574 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -50,7 +50,6 @@ android_test {
":PackageManagerTestAppVersion1",
],
- platform_apis: true,
sdk_version: "core_platform",
test_suites: ["device-tests"],
}
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
index 18d82afc5f75..966d362f1fd1 100644
--- a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -16,6 +16,7 @@
package android.content.pm
+import android.Manifest
import android.app.Instrumentation
import android.app.PendingIntent
import android.content.BroadcastReceiver
@@ -23,18 +24,23 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInstaller.SessionParams
+import android.os.Handler
+import android.os.HandlerThread
import android.platform.test.annotations.Presubmit
+import android.util.Log
import androidx.test.InstrumentationRegistry
import androidx.test.filters.LargeTest
import com.android.compatibility.common.util.ShellIdentityUtils
import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.testng.Assert.assertThrows
import java.util.concurrent.ArrayBlockingQueue
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.random.Random
+import org.junit.After
+import org.testng.Assert.assertThrows
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
/**
* For verifying public [PackageInstaller] session APIs. This differs from
@@ -65,27 +71,98 @@ class PackageSessionTests {
private const val INTENT_ACTION = "com.android.server.pm.test.test_app.action"
}
+ private val TAG = "PackageSessionTests"
private val context: Context = InstrumentationRegistry.getContext()
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-
private val installer = context.packageManager.packageInstaller
+ private var callback: SessionStatusTrackerCallback? = null
+ private var handlerThread: HandlerThread? = null
+ private var handler: Handler? = null
private val receiver = object : BroadcastReceiver() {
private val results = ArrayBlockingQueue<Intent>(1)
override fun onReceive(context: Context, intent: Intent) {
+ // Added as a safety net. Have observed instances where the Queue isn't empty which
+ // causes the test suite to crash.
+ if (results.size != 0) {
+ clear()
+ }
results.add(intent)
}
fun makeIntentSender(sessionId: Int) = PendingIntent.getBroadcast(context, sessionId,
Intent(INTENT_ACTION),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE_UNAUDITED).intentSender
+ PendingIntent.FLAG_UPDATE_CURRENT
+ or PendingIntent.FLAG_MUTABLE_UNAUDITED).intentSender
fun getResult(unit: TimeUnit, timeout: Long) = results.poll(timeout, unit)
fun clear() = results.clear()
}
+ class SessionStatusTrackerCallback : PackageInstaller.SessionCallback {
+ private val TAG: String = "SessionStatusTrackerCallback"
+ private val DEFAULT_TIMEOUT: Long = 30
+ private var mSessionActiveLatch: CountDownLatch? = null
+ private var mSessionInactiveLatch: CountDownLatch? = null
+ private var mSessionFinishLatch: CountDownLatch? = null
+ private val mSessionIds = mutableSetOf<Int>()
+
+ constructor(sessionActiveCount: Int = 0, sessionInactiveCount: Int = 0) {
+ this.mSessionActiveLatch = CountDownLatch(sessionActiveCount)
+ this.mSessionInactiveLatch = CountDownLatch(sessionInactiveCount)
+ }
+
+ constructor(sessionFinishCount: Int = 0) {
+ this.mSessionFinishLatch = CountDownLatch(sessionFinishCount)
+ }
+
+ override fun onCreated(sessionId: Int) {
+ mSessionIds.add(sessionId)
+ }
+
+ override fun onBadgingChanged(sessionId: Int) {}
+
+ override fun onActiveChanged(sessionId: Int, active: Boolean) {
+ if (mSessionIds.contains(sessionId)) {
+ if (active) {
+ mSessionActiveLatch?.countDown()
+ } else {
+ mSessionInactiveLatch?.countDown()
+ }
+ } else {
+ Log.d(TAG, "Did not find session ID $sessionId which was opened.")
+ }
+ }
+
+ override fun onProgressChanged(sessionId: Int, progress: Float) {}
+
+ override fun onFinished(sessionId: Int, success: Boolean) {
+ if (!success and mSessionIds.contains(sessionId)) {
+ mSessionFinishLatch?.countDown()
+ }
+ }
+
+ fun awaitSessionActiveCallbacks() {
+ mSessionActiveLatch?.await(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
+ }
+
+ fun awaitSessionInactiveCallbacks() {
+ mSessionInactiveLatch?.await(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
+ }
+
+ fun awaitSessionFinishCallbacks() {
+ mSessionFinishLatch?.await(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
+ }
+
+ fun resetLatches() {
+ mSessionActiveLatch = null
+ mSessionInactiveLatch = null
+ mSessionFinishLatch = null
+ }
+ }
+
@Before
fun registerReceiver() {
receiver.clear()
@@ -101,8 +178,7 @@ class PackageSessionTests {
@After
fun abandonAllSessions() {
instrumentation.uiAutomation
- .executeShellCommand("pm uninstall com.android.server.pm.test.test_app")
- .close()
+ .executeShellCommand("pm uninstall $TEST_PKG_NAME")
installer.mySessions.asSequence()
.map { it.sessionId }
@@ -110,11 +186,27 @@ class PackageSessionTests {
try {
installer.abandonSession(it)
} catch (ignored: Exception) {
+ Log.e(TAG, "Abandon failed: ", ignored)
// Querying for sessions checks by calling package name, but abandoning
// checks by UID, which won't match if this test failed to clean up
// on a previous install + run + uninstall, so ignore these failures.
}
}
+
+ // Abandoning sessions created by the @LargeTest takes time. We must ensure that all
+ // sessions are abandoned before proceeding with the next test. If all the sessions are not
+ // abandoned before starting a new test, we may encounter an IllegalStateException
+ callback?.apply {
+ awaitSessionFinishCallbacks()
+ resetLatches()
+ installer.unregisterSessionCallback(this)
+ }
+ }
+
+ @After
+ fun revokeShellPermissionsAndCloseThread() {
+ instrumentation.uiAutomation.dropShellPermissionIdentity()
+ handlerThread?.quitSafely()
}
@Test
@@ -199,6 +291,13 @@ class PackageSessionTests {
@LargeTest
@Test
fun allocateMaxSessionsWithPermission() {
+ // Already invoking with shell permissions. Using the function to setup the handler
+ setupHandlerAndPermissions(/* Need permissions? */false)
+
+ callback = SessionStatusTrackerCallback(sessionFinishCount = 1024)
+
+ installer.registerSessionCallback(callback!!, handler!!)
+
ShellIdentityUtils.invokeWithShellPermissions {
repeat(1024) { createDummySession() }
assertThrows(IllegalStateException::class.java) { createDummySession() }
@@ -208,10 +307,94 @@ class PackageSessionTests {
@LargeTest
@Test
fun allocateMaxSessionsNoPermission() {
+ setupHandlerAndPermissions(/* Need permissions? */false)
+
+ callback = SessionStatusTrackerCallback(sessionFinishCount = 50)
+
+ installer.registerSessionCallback(callback!!, handler!!)
+
repeat(50) { createDummySession() }
assertThrows(IllegalStateException::class.java) { createDummySession() }
}
+ @Test
+ fun whenGrantedInstallPermission_sessionIsActive() {
+ setupHandlerAndPermissions(true)
+
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
+ params.setRequireUserAction(SessionParams.USER_ACTION_REQUIRED)
+
+ callback = SessionStatusTrackerCallback(sessionActiveCount = 2, sessionInactiveCount = 1)
+
+ installer.registerSessionCallback(callback!!, handler!!)
+
+ val sessionId = installer.createSession(params)
+ // sessionActiveLatch counts down once when a session is opened
+ val session = installer.openSession(sessionId)
+
+ javaClass.classLoader.getResourceAsStream("PackageManagerTestAppVersion1.apk")!!
+ .use { input ->
+ session.openWrite("base", 0, -1)
+ .use { output -> input.copyTo(output) }
+ }
+
+ session.commit(receiver.makeIntentSender(sessionId))
+ session.close()
+
+ // Wait till we get one session change callback to with status 'inactive'
+ callback?.awaitSessionInactiveCallbacks()
+
+ val installStatus = receiver.getResult(TimeUnit.SECONDS, 30)
+ .getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE)
+
+ if (installStatus == PackageInstaller.STATUS_PENDING_USER_ACTION) {
+ installer.setPermissionsResult(sessionId, true)
+ } else {
+ fail("Did not wait for user action")
+ }
+
+ // sessionActiveLatch counts down the second time when install permission is granted.
+ // At this time, the latch opens.
+ callback?.awaitSessionActiveCallbacks()
+ assertThat(installer.getSessionInfo(sessionId)!!.isActive).isEqualTo(true)
+ }
+
+ @Test
+ fun whenWaitingForUserAction_sessionIsInactive() {
+ setupHandlerAndPermissions(true)
+
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
+ params.setRequireUserAction(SessionParams.USER_ACTION_REQUIRED)
+
+ callback = SessionStatusTrackerCallback(sessionActiveCount = 1, sessionInactiveCount = 1)
+
+ installer.registerSessionCallback(callback!!, handler!!)
+
+ val sessionId = installer.createSession(params)
+ val session = installer.openSession(sessionId)
+
+ // Wait till we get one session change callback to with status 'active'
+ callback?.awaitSessionActiveCallbacks()
+
+ javaClass.classLoader.getResourceAsStream("PackageManagerTestAppVersion1.apk")!!
+ .use { input ->
+ session.openWrite("base", 0, -1)
+ .use { output -> input.copyTo(output) }
+ }
+
+ session.commit(receiver.makeIntentSender(sessionId))
+ session.close()
+
+ // Wait till we get one session change callback to with status 'inactive'
+ callback?.awaitSessionInactiveCallbacks()
+
+ val installStatus = receiver.getResult(TimeUnit.SECONDS, 30)
+ .getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE)
+
+ assertThat(installStatus).isEqualTo(PackageInstaller.STATUS_PENDING_USER_ACTION)
+ assertThat(installer.getSessionInfo(sessionId)!!.isActive).isEqualTo(false)
+ }
+
private fun createDummySession() {
installer.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL)
.apply {
@@ -254,4 +437,15 @@ class PackageSessionTests {
installer.abandonSession(sessionId)
}
}
+
+ private fun setupHandlerAndPermissions(needPermissions: Boolean) {
+ if (needPermissions) {
+ instrumentation.uiAutomation.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.REQUEST_INSTALL_PACKAGES,
+ Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION)
+ }
+ handlerThread = HandlerThread("PackageSessionTests")
+ handlerThread?.start()
+ handler = Handler(handlerThread?.looper)
+ }
}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index f87797a90c90..2b34ee2646f3 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -36,7 +36,6 @@ android_test {
],
test_suites: ["general-tests"],
sdk_version: "test_current",
- platform_apis: true,
}
filegroup {
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index c1f3c4fc12c7..48c9df04a662 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -72,7 +72,6 @@ android_test {
"libpowermanagertest_jni",
],
- platform_apis: true,
sdk_version: "core_platform",
test_suites: ["device-tests"],
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 04857ec756d2..5ee19ccfbb90 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -161,6 +161,9 @@
<!-- ChooserActivityTest permissions-->
<uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
+ <!-- AccessibilityShortcutChooserActivityTest permissions -->
+ <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
+
<application android:theme="@style/Theme" android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
@@ -1411,6 +1414,7 @@
<activity android:name="com.android.internal.app.ChooserWrapperActivity"/>
<activity android:name="com.android.internal.app.ResolverWrapperActivity"/>
<activity android:name="com.android.internal.app.IntentForwarderActivityTest$IntentForwarderWrapperActivity"/>
+ <activity android:name="com.android.internal.accessibility.AccessibilityShortcutChooserActivityTest$TestAccessibilityShortcutChooserActivity"/>
<receiver android:name="android.app.activity.AbortReceiver"
android:exported="true">
diff --git a/core/tests/coretests/src/android/app/KeyguardManagerTest.java b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
new file mode 100644
index 000000000000..7231fbd3b7eb
--- /dev/null
+++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.app;
+
+import 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.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+@RunWith(JUnit4.class)
+public class KeyguardManagerTest {
+
+ private static final String TITLE = "Title";
+ private static final String DESCRIPTION = "Description";
+ private static final int USER_ID = 0;
+ private static final String PASSWORD = "PASSWORD";
+ private static final boolean DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = false;
+ private static final int PASSWORD_LOCK_TYPE = KeyguardManager.PASSWORD;
+ private static final int MEDIUM_PASSWORD_COMPLEXITY =
+ DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+
+
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
+ private final KeyguardManager mKeyguardManager = spy(
+ mContext.getSystemService(KeyguardManager.class));
+
+
+ @BeforeClass
+ public static void setup() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void createConfirmDeviceCredentialIntent_deviceSecure() {
+ when(mKeyguardManager.isDeviceSecure(USER_ID)).thenReturn(true);
+
+ Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(TITLE, DESCRIPTION,
+ USER_ID);
+
+ assertEquals(intent.getAction(),
+ KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
+ assertEquals(intent.getStringExtra(KeyguardManager.EXTRA_TITLE), TITLE);
+ assertEquals(intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION), DESCRIPTION);
+ assertEquals(intent.getIntExtra(Intent.EXTRA_USER_ID, /* defaultValue= */-1), USER_ID);
+ assertEquals(intent.getPackage(), "com.android.settings");
+ }
+
+ @Test
+ public void createConfirmDeviceCredentialIntent_deviceNotSecure() {
+ when(mKeyguardManager.isDeviceSecure(USER_ID)).thenReturn(false);
+
+ Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(TITLE, DESCRIPTION,
+ USER_ID);
+
+ assertNull(intent);
+ }
+
+ @Test
+ public void createConfirmDeviceCredentialIntent() {
+ when(mKeyguardManager.isDeviceSecure(USER_ID)).thenReturn(true);
+
+ Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(TITLE, DESCRIPTION,
+ USER_ID, DISALLOW_BIOMETRICS_IF_POLICY_EXISTS);
+
+ assertEquals(DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
+ intent.getBooleanExtra(KeyguardManager.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
+ !DISALLOW_BIOMETRICS_IF_POLICY_EXISTS));
+ }
+
+ @Test
+ public void setPrivateNotificationsAllowed_allowed() {
+ mKeyguardManager.setPrivateNotificationsAllowed(true);
+
+ assertTrue(mKeyguardManager.getPrivateNotificationsAllowed());
+ }
+
+ @Test
+ public void setPrivateNotificationsAllowed_notAllowed() {
+ mKeyguardManager.setPrivateNotificationsAllowed(false);
+
+ assertFalse(mKeyguardManager.getPrivateNotificationsAllowed());
+ }
+
+ @Test
+ public void setLock_setInitialLockPermissionGranted_validPassword() {
+ // Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
+ doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
+ doReturn(true).when(mKeyguardManager).isValidLockPasswordComplexity(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ boolean successfullySetLock = mKeyguardManager.setLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ assertTrue(successfullySetLock);
+
+ verifyDeviceLockedAndRemoveLock();
+ }
+
+ @Test
+ public void setLock_setInitialLockPermissionGranted_invalidPassword() {
+ // Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
+ doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
+ doReturn(false).when(mKeyguardManager).isValidLockPasswordComplexity(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ boolean successfullySetLock = mKeyguardManager.setLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ assertFalse(successfullySetLock);
+ assertFalse(mKeyguardManager.isDeviceSecure());
+ }
+
+ @Test
+ public void setLock_setInitialLockPermissionDenied() {
+ // Set to `false` to behave as if SET_INITIAL_LOCK permission had not been granted.
+ doReturn(false).when(mKeyguardManager).checkInitialLockMethodUsage();
+ assertFalse(mKeyguardManager.checkInitialLockMethodUsage());
+
+ boolean successfullySetLock = mKeyguardManager.setLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ assertFalse(successfullySetLock);
+ assertFalse(mKeyguardManager.isDeviceSecure());
+ }
+
+ @Test
+ public void checkLock_correctCredentials() {
+ // Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
+ doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
+ doReturn(true).when(mKeyguardManager).isValidLockPasswordComplexity(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+ mKeyguardManager.setLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ boolean correctLockCredentials = mKeyguardManager.checkLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes());
+
+ assertTrue(correctLockCredentials);
+
+ verifyDeviceLockedAndRemoveLock();
+ }
+
+ @Test
+ public void checkLock_incorrectCredentials() {
+ // Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
+ doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
+ doReturn(true).when(mKeyguardManager).isValidLockPasswordComplexity(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+ mKeyguardManager.setLock(PASSWORD_LOCK_TYPE,
+ PASSWORD.getBytes(),
+ MEDIUM_PASSWORD_COMPLEXITY);
+
+ boolean correctLockCredentials = mKeyguardManager.checkLock(PASSWORD_LOCK_TYPE,
+ "INCORRECT PASSWORD".getBytes());
+
+ assertFalse(correctLockCredentials);
+
+ verifyDeviceLockedAndRemoveLock();
+ }
+
+ private void verifyDeviceLockedAndRemoveLock() {
+ assertTrue(mKeyguardManager.isDeviceSecure());
+ assertTrue("Failed to remove new password that was set in the test case.",
+ mKeyguardManager.setLock(-1, null, PASSWORD_LOCK_TYPE, PASSWORD.getBytes()));
+ }
+}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index bfb2fd57975f..a2d4bafef41c 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -31,7 +31,6 @@ import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.IApplicationThread;
@@ -571,53 +570,6 @@ public class ActivityThreadTest {
}
@Test
- public void testHandleProcessConfigurationChanged_DependOnProcessState() {
- final ActivityThread activityThread = ActivityThread.currentActivityThread();
- final Configuration origConfig = activityThread.getConfiguration();
- final int newDpi = origConfig.densityDpi + 10;
- final Configuration newConfig = new Configuration(origConfig);
- newConfig.seq++;
- newConfig.densityDpi = newDpi;
-
- activityThread.updateProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- false /* fromIPC */);
-
- applyProcessConfiguration(activityThread, newConfig);
- try {
- // In the cached state, the configuration is only set as pending and not applied.
- assertEquals(origConfig.densityDpi, activityThread.getConfiguration().densityDpi);
- assertTrue(activityThread.isCachedProcessState());
- } finally {
- // The foreground state is the default state of instrumentation.
- activityThread.updateProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- false /* fromIPC */);
- }
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
- try {
- // The state becomes non-cached, the pending configuration should be applied.
- assertEquals(newConfig.densityDpi, activityThread.getConfiguration().densityDpi);
- assertFalse(activityThread.isCachedProcessState());
- } finally {
- // Restore to the original configuration.
- activityThread.getConfiguration().seq = origConfig.seq - 1;
- applyProcessConfiguration(activityThread, origConfig);
- }
- }
-
- private static void applyProcessConfiguration(ActivityThread thread, Configuration config) {
- final ClientTransaction clientTransaction = newTransaction(thread,
- null /* activityToken */);
- clientTransaction.addCallback(ConfigurationChangeItem.obtain(config));
- final IApplicationThread appThread = thread.getApplicationThread();
- try {
- appThread.scheduleTransaction(clientTransaction);
- } catch (Exception ignored) {
- }
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
- @Test
public void testResumeAfterNewIntent() {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final ActivityThread activityThread = activity.getActivityThread();
diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
new file mode 100644
index 000000000000..90b33058d4e8
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.time;
+
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.ShellCommand;
+
+import org.junit.Test;
+
+/**
+ * Tests for non-SDK methods on {@link ExternalTimeSuggestion}.
+ * Also see {@link android.app.time.cts.ExternalTimeSuggestionTest}
+ */
+public class ExternalTimeSuggestionTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noReferenceTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--unix_epoch_time 12345");
+ ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noUnixEpochTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321");
+ ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test
+ public void testParseCommandLineArg_validSuggestion() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345");
+ ExternalTimeSuggestion expectedSuggestion = new ExternalTimeSuggestion(54321L, 12345L);
+ ExternalTimeSuggestion actualSuggestion =
+ ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+ assertEquals(expectedSuggestion, actualSuggestion);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_unknownArgument() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+ ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+}
diff --git a/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
index 85073b0ecfdd..9d7dde2141bb 100644
--- a/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
@@ -17,6 +17,7 @@
package android.app.time;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
@@ -24,6 +25,9 @@ import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTrip
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import android.os.UserHandle;
@@ -38,22 +42,80 @@ import org.junit.runner.RunWith;
@SmallTest
public class TimeCapabilitiesTest {
- private static final UserHandle USER_HANDLE = UserHandle.of(332211);
+ private static final UserHandle TEST_USER_HANDLE = UserHandle.of(332211);
+
+ @Test
+ public void testEquals() {
+ TimeCapabilities.Builder builder1 = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED);
+ TimeCapabilities.Builder builder2 = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED);
+ {
+ TimeCapabilities one = builder1.build();
+ TimeCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder2.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeCapabilities one = builder1.build();
+ TimeCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeCapabilities one = builder1.build();
+ TimeCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder2.setSuggestManualTimeCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeCapabilities one = builder1.build();
+ TimeCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setSuggestManualTimeCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeCapabilities one = builder1.build();
+ TimeCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+ }
+
+ @Test
+ public void userHandle_notIgnoredInEquals() {
+ TimeCapabilities firstUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(1))
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED)
+ .build();
+
+ TimeCapabilities secondUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(2))
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED)
+ .build();
+
+ assertThat(firstUserCapabilities).isNotEqualTo(secondUserCapabilities);
+ }
@Test
public void testBuilder() {
- TimeCapabilities capabilities = new TimeCapabilities.Builder(USER_HANDLE)
- .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
- .setSuggestTimeManuallyCapability(CAPABILITY_NOT_SUPPORTED)
+ TimeCapabilities capabilities = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_SUPPORTED)
.build();
- assertThat(capabilities.getConfigureAutoTimeDetectionEnabledCapability())
+ assertThat(capabilities.getConfigureAutoDetectionEnabledCapability())
.isEqualTo(CAPABILITY_NOT_APPLICABLE);
- assertThat(capabilities.getSuggestTimeManuallyCapability())
+ assertThat(capabilities.getSuggestManualTimeCapability())
.isEqualTo(CAPABILITY_NOT_SUPPORTED);
try {
- new TimeCapabilities.Builder(USER_HANDLE)
+ new TimeCapabilities.Builder(TEST_USER_HANDLE)
.build();
fail("Should throw IllegalStateException");
} catch (IllegalStateException ignored) {
@@ -61,8 +123,8 @@ public class TimeCapabilitiesTest {
}
try {
- new TimeCapabilities.Builder(USER_HANDLE)
- .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
+ new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
.build();
fail("Should throw IllegalStateException");
} catch (IllegalStateException ignored) {
@@ -70,8 +132,8 @@ public class TimeCapabilitiesTest {
}
try {
- new TimeCapabilities.Builder(USER_HANDLE)
- .setSuggestTimeManuallyCapability(CAPABILITY_NOT_APPLICABLE)
+ new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_APPLICABLE)
.build();
fail("Should throw IllegalStateException");
} catch (IllegalStateException ignored) {
@@ -80,33 +142,93 @@ public class TimeCapabilitiesTest {
}
@Test
- public void userHandle_notIgnoredInEquals() {
- TimeCapabilities firstUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(1))
- .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED)
- .setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED)
+ public void testParcelable() {
+ TimeCapabilities.Builder builder = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_SUPPORTED)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_SUPPORTED);
+
+ assertRoundTripParcelable(builder.build());
+
+ builder.setSuggestManualTimeCapability(CAPABILITY_POSSESSED);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED);
+ assertRoundTripParcelable(builder.build());
+ }
+
+ @Test
+ public void testTryApplyConfigChanges_permitted() {
+ TimeConfiguration oldConfiguration =
+ new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .build();
+ TimeCapabilities capabilities = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED)
.build();
- TimeCapabilities secondUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(2))
- .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED)
- .setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED)
+ TimeConfiguration configChange = new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(false)
.build();
- assertThat(firstUserCapabilities).isNotEqualTo(secondUserCapabilities);
+ TimeConfiguration expected = new TimeConfiguration.Builder(oldConfiguration)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertEquals(expected, capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
}
@Test
- public void testParcelable() {
- TimeCapabilities.Builder builder = new TimeCapabilities.Builder(USER_HANDLE)
- .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_SUPPORTED)
- .setSuggestTimeManuallyCapability(CAPABILITY_NOT_SUPPORTED);
-
- assertRoundTripParcelable(builder.build());
+ public void testTryApplyConfigChanges_notPermitted() {
+ TimeConfiguration oldConfiguration =
+ new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .build();
+ TimeCapabilities capabilities = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_ALLOWED)
+ .build();
- builder.setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED);
- assertRoundTripParcelable(builder.build());
+ TimeConfiguration configChange = new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(false)
+ .build();
- builder.setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED);
- assertRoundTripParcelable(builder.build());
+ assertNull(capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
}
+ @Test
+ public void copyBuilder_copiesAllFields() {
+ TimeCapabilities capabilities = new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_ALLOWED)
+ .build();
+
+ {
+ TimeCapabilities updatedCapabilities =
+ new TimeCapabilities.Builder(capabilities)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .build();
+ TimeCapabilities expectedCapabilities =
+ new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeCapability(CAPABILITY_NOT_ALLOWED)
+ .build();
+
+ assertThat(updatedCapabilities).isEqualTo(expectedCapabilities);
+ }
+
+ {
+ TimeCapabilities updatedCapabilities =
+ new TimeCapabilities.Builder(capabilities)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED)
+ .build();
+
+ TimeCapabilities expectedCapabilities =
+ new TimeCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeCapability(CAPABILITY_POSSESSED)
+ .build();
+
+ assertThat(updatedCapabilities).isEqualTo(expectedCapabilities);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
index e248010319e1..af403a20ae7b 100644
--- a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
@@ -18,10 +18,12 @@ package android.app.timedetector;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
import org.junit.Test;
@@ -63,4 +65,36 @@ public class GnssTimeSuggestionTest {
GnssTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noReferenceTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--unix_epoch_time 12345");
+ GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noUnixEpochTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321");
+ GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test
+ public void testParseCommandLineArg_validSuggestion() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345");
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+ GnssTimeSuggestion expectedSuggestion = new GnssTimeSuggestion(timeSignal);
+ GnssTimeSuggestion actualSuggestion =
+ GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+ assertEquals(expectedSuggestion, actualSuggestion);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_unknownArgument() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+ GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
}
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index 750ffa1c9a54..94218cdea0ed 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -18,10 +18,12 @@ package android.app.timedetector;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
import org.junit.Test;
@@ -63,4 +65,36 @@ public class ManualTimeSuggestionTest {
ManualTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noReferenceTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--unix_epoch_time 12345");
+ ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noUnixEpochTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321");
+ ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test
+ public void testParseCommandLineArg_validSuggestion() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345");
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+ ManualTimeSuggestion expectedSuggestion = new ManualTimeSuggestion(timeSignal);
+ ManualTimeSuggestion actualSuggestion =
+ ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+ assertEquals(expectedSuggestion, actualSuggestion);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_unknownArgument() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+ ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
}
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
index b88c36f20bc6..0e09dd3e9aab 100644
--- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -18,10 +18,12 @@ package android.app.timedetector;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
import org.junit.Test;
@@ -63,4 +65,36 @@ public class NetworkTimeSuggestionTest {
NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noReferenceTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--unix_epoch_time 12345");
+ NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noUnixEpochTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321");
+ NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test
+ public void testParseCommandLineArg_validSuggestion() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345");
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+ NetworkTimeSuggestion expectedSuggestion = new NetworkTimeSuggestion(timeSignal);
+ NetworkTimeSuggestion actualSuggestion =
+ NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+ assertEquals(expectedSuggestion, actualSuggestion);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_unknownArgument() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+ NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
}
diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
index cc7557977e80..bb995a852637 100644
--- a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
@@ -18,10 +18,12 @@ package android.app.timedetector;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import android.os.ShellCommand;
import android.os.TimestampedValue;
import org.junit.Test;
@@ -95,4 +97,45 @@ public class TelephonyTimeSuggestionTest {
assertEquals(suggestion1.getDebugInfo(), rtSuggestion1.getDebugInfo());
}
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noSlotIndex() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--reference_time 54321 --unix_epoch_time 12345");
+ TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noReferenceTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--slot_index 0 --unix_epoch_time 12345");
+ TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_noUnixEpochTime() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--slot_index 0 --reference_time 54321");
+ TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
+
+ @Test
+ public void testParseCommandLineArg_validSuggestion() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345");
+ TelephonyTimeSuggestion expectedSuggestion =
+ new TelephonyTimeSuggestion.Builder(0)
+ .setUnixEpochTime(new TimestampedValue<>(54321L, 12345L))
+ .build();
+ TelephonyTimeSuggestion actualSuggestion =
+ TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+ assertEquals(expectedSuggestion, actualSuggestion);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseCommandLineArg_unknownArgument() {
+ ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+ "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+ TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+ }
}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
index 8d8290c7bdc9..4efaed11168e 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
@@ -26,14 +26,14 @@ import java.util.Arrays;
import java.util.List;
/** Utility methods related to {@link ShellCommand} objects used in several tests. */
-final class ShellCommandTestSupport {
+public final class ShellCommandTestSupport {
private ShellCommandTestSupport() {}
- static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
+ public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
}
- static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
+ public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
ShellCommand command = mock(ShellCommand.class);
class ArgProvider {
private int mCount;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 0ebf03fab966..925da4968517 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
+import android.graphics.text.LineBreakConfig;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
import android.text.Layout.Alignment;
@@ -925,4 +926,24 @@ public class StaticLayoutTest {
assertEquals(0, layout.getHeight(true));
assertEquals(2, layout.getLineCount());
}
+
+ @Test
+ public void testBuilder_autoPhraseBreaking() {
+ {
+ // setAutoPhraseBreaking true
+ LineBreakConfig lineBreakConfig = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .setAutoPhraseBreaking(true)
+ .build();
+ final String text = "これが正解。";
+ // Obtain.
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0,
+ text.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setLineBreakConfig(lineBreakConfig);
+ builder.build();
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
+ builder.getLineBreakWordStyle());
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/text/TextShaperTest.java b/core/tests/coretests/src/android/text/TextShaperTest.java
index 8237cb0bb243..77b14e6fa57f 100644
--- a/core/tests/coretests/src/android/text/TextShaperTest.java
+++ b/core/tests/coretests/src/android/text/TextShaperTest.java
@@ -16,7 +16,10 @@
package android.text;
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.graphics.fonts.Font;
+import android.graphics.fonts.FontFileUtil;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +34,16 @@ public class TextShaperTest {
@Test
public void testFontWithPath() {
TextPaint p = new TextPaint();
- p.setFontFeatureSettings("'wght' 900");
+ p.setFontVariationSettings("'wght' 900");
TextShaper.shapeText("a", 0, 1, TextDirectionHeuristics.LTR, p,
(start, end, glyphs, paint) -> {
// This test only passes if the font of the Latin font is variable font.
- assertThat(glyphs.getFont(0).getFile()).isNotNull();
+ Font font = glyphs.getFont(0);
+ String psName = FontFileUtil.getPostScriptName(font.getBuffer(), 0);
+ String message = "psName = " + psName + ", file = " + font.getFile();
+ assertWithMessage(message).that(glyphs.getFont(0).getFile())
+ .isNotNull();
+
});
}
}
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 5612833e5ddd..986cee55a108 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -36,6 +36,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.math.BigDecimal;
+import java.math.MathContext;
import java.util.Locale;
@Presubmit
@@ -216,6 +218,57 @@ public class FormatterTest {
mContext, 1 * SECOND));
}
+ /**
+ * Regression test for http://b/71580745 and https://unicode-org.atlassian.net/browse/CLDR-10831
+ */
+ @Test
+ public void testFormatFileSize_zhCN() {
+ setLocale(Locale.forLanguageTag("zh-CN"));
+
+ assertFormatFileSize_englishOutput();
+ }
+
+ @Test
+ public void testFormatFileSize_enUS() {
+ setLocale(Locale.US);
+
+ assertFormatFileSize_englishOutput();
+ }
+
+ private void assertFormatFileSize_englishOutput() {
+ final MathContext mc = MathContext.DECIMAL64;
+ final BigDecimal bd = new BigDecimal((long) 1000, mc);
+ // test null Context
+ assertEquals("", Formatter.formatFileSize(null, 0));
+ // test different long values with various length
+ assertEquals("0 B", Formatter.formatFileSize(mContext, 0));
+ assertEquals("1 B", Formatter.formatFileSize(mContext, 1));
+ assertEquals("9 B", Formatter.formatFileSize(mContext, 9));
+ assertEquals("10 B", Formatter.formatFileSize(mContext, 10));
+ assertEquals("99 B", Formatter.formatFileSize(mContext, 99));
+ assertEquals("100 B", Formatter.formatFileSize(mContext, 100));
+ assertEquals("900 B", Formatter.formatFileSize(mContext, 900));
+ assertEquals("0.90 kB", Formatter.formatFileSize(mContext, 901));
+
+ assertEquals("1.00 kB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
+ assertEquals("1.50 kB", Formatter.formatFileSize(mContext, bd.pow(1).longValue() * 3 / 2));
+ assertEquals("12.50 kB", Formatter.formatFileSize(mContext,
+ bd.pow(1).longValue() * 25 / 2));
+
+ assertEquals("1.00 MB", Formatter.formatFileSize(mContext, bd.pow(2).longValue()));
+
+ assertEquals("1.00 GB", Formatter.formatFileSize(mContext, bd.pow(3).longValue()));
+
+ assertEquals("1.00 TB", Formatter.formatFileSize(mContext, bd.pow(4).longValue()));
+
+ assertEquals("1.00 PB", Formatter.formatFileSize(mContext, bd.pow(5).longValue()));
+
+ assertEquals("1000 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
+
+ // test Negative value
+ assertEquals("-1 B", Formatter.formatFileSize(mContext, -1));
+ }
+
private void checkFormatBytes(long bytes, boolean useShort,
String expectedString, long expectedRounded) {
checkFormatBytes(bytes, (useShort ? Formatter.FLAG_SHORTER : 0),
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
index c636912ee98d..fe7d28917670 100644
--- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
@@ -26,14 +28,20 @@ import static org.mockito.ArgumentMatchers.anyInt;
import android.annotation.Nullable;
import android.graphics.BlurMaskFilter;
+import android.os.Bundle;
+import android.os.LocaleList;
import android.os.Parcel;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.MaskFilterSpan;
import android.text.style.UnderlineSpan;
+import android.util.StringBuilderPrinter;
+import android.view.autofill.AutofillId;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -44,6 +52,7 @@ import org.junit.runner.RunWith;
/**
* Supplemental tests that cannot be covered by CTS (e.g. due to hidden API dependencies).
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class EditorInfoTest {
@@ -449,4 +458,72 @@ public class EditorInfoTest {
}
return builder;
}
+
+ @Test
+ public void testDump_empty() {
+ final EditorInfo info = new EditorInfo();
+ final StringBuilder sb = new StringBuilder();
+ info.dump(new StringBuilderPrinter(sb), "prefix: ");
+ assertThat(sb.toString()).isEqualTo(
+ "prefix: inputType=0x0 imeOptions=0x0 privateImeOptions=null\n"
+ + "prefix: actionLabel=null actionId=0\n"
+ + "prefix: initialSelStart=-1 initialSelEnd=-1 initialCapsMode=0x0\n"
+ + "prefix: hintText=null label=null\n"
+ + "prefix: packageName=null autofillId=null fieldId=0 fieldName=null\n"
+ + "prefix: extras=null\n"
+ + "prefix: hintLocales=null\n"
+ + "prefix: contentMimeTypes=null\n");
+ }
+
+ @Test
+ public void testDump_filled() {
+ final EditorInfo info = new EditorInfo();
+ info.inputType = InputType.TYPE_CLASS_TEXT; // 0x1
+ info.imeOptions = EditorInfo.IME_ACTION_GO; // 0x2
+ info.privateImeOptions = "testOptions";
+ info.initialSelStart = 0;
+ info.initialSelEnd = 1;
+ info.initialCapsMode = TextUtils.CAP_MODE_CHARACTERS; // 0x1000
+ info.hintText = "testHintText";
+ info.label = "testLabel";
+ info.packageName = "android.view.inputmethod";
+ info.autofillId = new AutofillId(123);
+ info.fieldId = 456;
+ info.fieldName = "testField";
+ info.extras = new Bundle();
+ info.extras.putString("testKey", "testValue");
+ info.hintLocales = LocaleList.forLanguageTags("en,es,zh");
+ info.contentMimeTypes = new String[] {"image/png"};
+ info.targetInputMethodUser = UserHandle.of(10);
+ final StringBuilder sb = new StringBuilder();
+ info.dump(new StringBuilderPrinter(sb), "prefix2: ");
+ assertThat(sb.toString()).isEqualTo(
+ "prefix2: inputType=0x1 imeOptions=0x2 privateImeOptions=testOptions\n"
+ + "prefix2: actionLabel=null actionId=0\n"
+ + "prefix2: initialSelStart=0 initialSelEnd=1 initialCapsMode=0x1000\n"
+ + "prefix2: hintText=testHintText label=testLabel\n"
+ + "prefix2: packageName=android.view.inputmethod autofillId=123"
+ + " fieldId=456 fieldName=testField\n"
+ + "prefix2: extras=Bundle[{testKey=testValue}]\n"
+ + "prefix2: hintLocales=[en,es,zh]\n"
+ + "prefix2: contentMimeTypes=[image/png]\n"
+ + "prefix2: targetInputMethodUserId=10\n");
+ }
+
+ @Test
+ public void testDump_noDumpExtras() {
+ final EditorInfo info = new EditorInfo();
+ info.extras = new Bundle();
+ info.extras.putString("testKey", "testValue");
+ final StringBuilder sb = new StringBuilder();
+ info.dump(new StringBuilderPrinter(sb), "prefix: ", false /* dumpExtras */);
+ assertThat(sb.toString()).isEqualTo(
+ "prefix: inputType=0x0 imeOptions=0x0 privateImeOptions=null\n"
+ + "prefix: actionLabel=null actionId=0\n"
+ + "prefix: initialSelStart=-1 initialSelEnd=-1 initialCapsMode=0x0\n"
+ + "prefix: hintText=null label=null\n"
+ + "prefix: packageName=null autofillId=null fieldId=0 fieldName=null\n"
+ + "prefix: hintLocales=null\n"
+ + "prefix: contentMimeTypes=null\n");
+ }
}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index e303934c4aad..647e410d8c28 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -23,12 +23,10 @@ import static android.view.stylus.HandwritingTestUtil.createView;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.content.Context;
@@ -59,26 +57,36 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class HandwritingInitiatorTest {
- private static final int TOUCH_SLOP = 8;
private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
+ private static final int HW_BOUNDS_OFFSETS_LEFT_PX = 10;
+ private static final int HW_BOUNDS_OFFSETS_TOP_PX = 20;
+ private static final int HW_BOUNDS_OFFSETS_RIGHT_PX = 30;
+ private static final int HW_BOUNDS_OFFSETS_BOTTOM_PX = 40;
+ private int mHandwritingSlop = 4;
+
private static final Rect sHwArea = new Rect(100, 200, 500, 500);
private HandwritingInitiator mHandwritingInitiator;
private View mTestView;
- private Context mContext;
+ private Context mContext;
@Before
public void setup() {
final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
- ViewConfiguration viewConfiguration = mock(ViewConfiguration.class);
- when(viewConfiguration.getScaledTouchSlop()).thenReturn(TOUCH_SLOP);
+
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(mContext);
+ mHandwritingSlop = viewConfiguration.getScaledHandwritingSlop();
InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
mHandwritingInitiator =
spy(new HandwritingInitiator(viewConfiguration, inputMethodManager));
- mTestView = createView(sHwArea, true);
+ mTestView = createView(sHwArea, true,
+ HW_BOUNDS_OFFSETS_LEFT_PX,
+ HW_BOUNDS_OFFSETS_TOP_PX,
+ HW_BOUNDS_OFFSETS_RIGHT_PX,
+ HW_BOUNDS_OFFSETS_BOTTOM_PX);
mHandwritingInitiator.updateHandwritingAreasForView(mTestView);
}
@@ -90,7 +98,7 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
@@ -108,13 +116,13 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
- final int x3 = x2 + TOUCH_SLOP * 2;
+ final int x3 = x2 + mHandwritingSlop * 2;
final int y3 = y2;
MotionEvent stylusEvent3 = createStylusEvent(ACTION_MOVE, x3, y3, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent3);
@@ -127,13 +135,49 @@ public class HandwritingInitiatorTest {
}
@Test
+ public void onTouchEvent_startHandwriting_when_stylusMove_withinExtendedHWArea() {
+ mHandwritingInitiator.onInputConnectionCreated(mTestView);
+ final int x1 = sHwArea.left - HW_BOUNDS_OFFSETS_LEFT_PX / 2;
+ final int y1 = sHwArea.top - HW_BOUNDS_OFFSETS_TOP_PX / 2;
+ MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+ final int x2 = x1 + mHandwritingSlop * 2;
+ final int y2 = y1;
+
+ MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+ // Stylus movement within extended HandwritingArea should trigger IMM.startHandwriting once.
+ verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
+ }
+
+ @Test
public void onTouchEvent_startHandwriting_inputConnectionBuiltAfterStylusMove() {
final int x1 = (sHwArea.left + sHwArea.right) / 2;
final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
+ final int y2 = y1;
+ MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+ // InputConnection is created after stylus movement.
+ mHandwritingInitiator.onInputConnectionCreated(mTestView);
+
+ verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
+ }
+
+ @Test
+ public void onTouchEvent_startHandwriting_inputConnectionBuilt_stylusMoveInExtendedHWArea() {
+ final int x1 = sHwArea.right + HW_BOUNDS_OFFSETS_RIGHT_PX / 2;
+ final int y1 = sHwArea.bottom + HW_BOUNDS_OFFSETS_BOTTOM_PX / 2;
+ MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
@@ -152,7 +196,7 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP / 2;
+ final int x2 = x1 + mHandwritingSlop / 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_UP, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
@@ -168,7 +212,7 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
@@ -185,7 +229,7 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
final long time2 = time1 + TIMEOUT + 10L;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
@@ -202,7 +246,24 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
+ final int y2 = y1;
+
+ MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+ // HandwritingInitiator will request focus for the registered view.
+ verify(mTestView, times(1)).requestFocus();
+ }
+
+ @Test
+ public void onTouchEvent_focusView_stylusMoveOnce_withinExtendedHWArea() {
+ final int x1 = sHwArea.left - HW_BOUNDS_OFFSETS_LEFT_PX / 2;
+ final int y1 = sHwArea.top - HW_BOUNDS_OFFSETS_TOP_PX / 2;
+ MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
@@ -221,7 +282,7 @@ public class HandwritingInitiatorTest {
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent1);
- final int x2 = x1 + TOUCH_SLOP * 2;
+ final int x2 = x1 + mHandwritingSlop * 2;
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
index 6daf880fa2ab..e6e50e908680 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -33,6 +33,12 @@ public class HandwritingTestUtil {
}
public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled) {
+ return createView(handwritingArea, autoHandwritingEnabled, 0, 0, 0, 0);
+ }
+
+ public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
+ float handwritingBoundsOffsetLeft, float handwritingBoundsOffsetTop,
+ float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
final Context context = instrumentation.getTargetContext();
// mock a parent so that HandwritingInitiator can get
@@ -52,6 +58,10 @@ public class HandwritingTestUtil {
when(view.isAttachedToWindow()).thenReturn(true);
when(view.isAggregatedVisible()).thenReturn(true);
when(view.getHandwritingArea()).thenReturn(handwritingArea);
+ when(view.getHandwritingBoundsOffsetLeft()).thenReturn(handwritingBoundsOffsetLeft);
+ when(view.getHandwritingBoundsOffsetTop()).thenReturn(handwritingBoundsOffsetTop);
+ when(view.getHandwritingBoundsOffsetRight()).thenReturn(handwritingBoundsOffsetRight);
+ when(view.getHandwritingBoundsOffsetBottom()).thenReturn(handwritingBoundsOffsetBottom);
view.setAutoHandwritingEnabled(autoHandwritingEnabled);
parent.addView(view);
return view;
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
index ce69f12a065b..678eef557fed 100644
--- a/core/tests/coretests/src/android/window/BackNavigationTest.java
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -91,7 +91,7 @@ public class BackNavigationTest {
private void assertCallbackIsCalled(CountDownLatch latch) {
try {
mInstrumentation.getUiAutomation().waitForIdle(500, 1000);
- BackNavigationInfo info = ActivityTaskManager.getService().startBackNavigation(true);
+ BackNavigationInfo info = ActivityTaskManager.getService().startBackNavigation();
assertNotNull("BackNavigationInfo is null", info);
assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback());
info.getOnBackInvokedCallback().onBackInvoked();
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
new file mode 100644
index 000000000000..425253281b48
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.accessibility;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.doubleClick;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isDialog;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+
+/**
+ * Tests for {@link AccessibilityShortcutChooserActivity}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityShortcutChooserActivityTest {
+ private static final String TEST_LABEL = "TEST_LABEL";
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getContext();
+ private ActivityScenario<TestAccessibilityShortcutChooserActivity> mScenario;
+ private static IAccessibilityManager sAccessibilityManagerService;
+
+ @Mock
+ private AccessibilityServiceInfo mAccessibilityServiceInfo;
+
+ @Mock
+ private ResolveInfo mResolveInfo;
+
+ @Mock
+ private ServiceInfo mServiceInfo;
+
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ sAccessibilityManagerService = mock(IAccessibilityManager.class);
+
+ when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
+ mResolveInfo.serviceInfo = mServiceInfo;
+ mServiceInfo.applicationInfo = mApplicationInfo;
+ when(mResolveInfo.loadLabel(any(PackageManager.class))).thenReturn(TEST_LABEL);
+ when(mAccessibilityServiceInfo.getComponentName()).thenReturn(
+ new ComponentName("package", "class"));
+ when(sAccessibilityManagerService.getInstalledAccessibilityServiceList(
+ anyInt())).thenReturn(Collections.singletonList(mAccessibilityServiceInfo));
+
+ mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+ }
+
+ @Test
+ public void doubleClickServiceTargetAndClickDenyButton_permissionDialogDoesNotExist() {
+ mScenario.moveToState(Lifecycle.State.CREATED);
+ mScenario.moveToState(Lifecycle.State.STARTED);
+ mScenario.moveToState(Lifecycle.State.RESUMED);
+ onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
+ isDialog()).check(matches(isDisplayed()));
+ onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
+
+ onView(withText(TEST_LABEL)).perform(doubleClick());
+ onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
+ matches(isDisplayed()));
+ onView(withId(R.id.accessibility_permission_enable_deny_button)).inRoot(isDialog()).check(
+ matches(isDisplayed()));
+ onView(withId(R.id.accessibility_permission_enable_deny_button)).perform(click());
+
+ onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
+ doesNotExist());
+ mScenario.moveToState(Lifecycle.State.DESTROYED);
+ }
+
+ /**
+ * Used for testing.
+ */
+ public static class TestAccessibilityShortcutChooserActivity extends
+ AccessibilityShortcutChooserActivity {
+ private AccessibilityManager mAccessibilityManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mAccessibilityManager = new AccessibilityManager(sContext, new Handler(getMainLooper()),
+ sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.ACCESSIBILITY_SERVICE.equals(name)) {
+ return mAccessibilityManager;
+ }
+
+ return super.getSystemService(name);
+ }
+ }
+}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f7c2b732a77b..547144f6ce1a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -163,6 +163,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1941440781": {
+ "message": "Creating Pending Move-to-back: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1939861963": {
"message": "Create root task displayId=%d winMode=%d",
"level": "VERBOSE",
@@ -469,6 +475,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
},
+ "-1635750891": {
+ "message": "Received remote change for Display[%d], applied: [%dx%d, rot = %d]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"-1633115609": {
"message": "Key dispatch not paused for screen off",
"level": "VERBOSE",
@@ -757,6 +769,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1383884640": {
+ "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1376035390": {
"message": "No task found",
"level": "DEBUG",
@@ -889,6 +907,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1256520588": {
+ "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_BOOT",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-1248645819": {
"message": "\tAdd container=%s",
"level": "DEBUG",
@@ -1519,12 +1543,6 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/TransitionController.java"
},
- "-618015844": {
- "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b mOnlyCore=%b. %s",
- "level": "INFO",
- "group": "WM_DEBUG_BOOT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-597091183": {
"message": "Delete TaskDisplayArea uid=%d",
"level": "VERBOSE",
@@ -2071,6 +2089,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-57572004": {
+ "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b canCustomizeAppTransition=%b Callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+ "at": "com\/android\/server\/wm\/AppTransition.java"
+ },
"-55185509": {
"message": "setFocusedTask: taskId=%d touchedActivity=%s",
"level": "DEBUG",
@@ -2143,6 +2167,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "25888308": {
+ "message": "Resize reasons for w=%s: %s configChanged=%b dragResizingChanged=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_RESIZE",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"35398067": {
"message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
"level": "DEBUG",
@@ -2527,12 +2557,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "352982444": {
- "message": " allReady query: used=%b override=%b states=[%s]",
- "level": "VERBOSE",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/Transition.java"
- },
"355720268": {
"message": "stopFreezingDisplayLocked: Unfreezing now",
"level": "DEBUG",
@@ -2797,12 +2821,6 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "625447638": {
- "message": "Resize reasons for w=%s: %s configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_RESIZE",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"628276090": {
"message": "Delaying app transition for screen rotation animation to finish",
"level": "VERBOSE",
@@ -3049,6 +3067,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "898260097": {
+ "message": "Creating Pending Pip-Enter: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"898863925": {
"message": "Attempted to add QS dialog window with unknown token %s. Aborting.",
"level": "WARN",
@@ -3379,12 +3403,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1246035185": {
- "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteRotation=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"1252594551": {
"message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
"level": "WARN",
@@ -3481,6 +3499,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
+ "1360176455": {
+ "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"1364126018": {
"message": "Resumed activity; dropping state of: %s",
"level": "INFO",
@@ -3505,6 +3529,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
+ "1393721079": {
+ "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"1396893178": {
"message": "createRootTask unknown displayId=%d",
"level": "ERROR",
@@ -3847,6 +3877,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "1764619787": {
+ "message": "Remote change for Display[%d]: timeout reached",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+ },
"1774661765": {
"message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
"level": "WARN",
@@ -4171,6 +4207,12 @@
"group": "WM_DEBUG_ANIM",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "2079410261": {
+ "message": "applyAnimation: override requested, but it is prohibited by policy.",
+ "level": "ERROR",
+ "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+ "at": "com\/android\/server\/wm\/AppTransition.java"
+ },
"2083556954": {
"message": "Set mOrientationChanging of %s",
"level": "VERBOSE",
@@ -4224,12 +4266,6 @@
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
- },
- "2137411379": {
- "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
- "at": "com\/android\/server\/wm\/AppTransition.java"
}
},
"groups": {
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index c81473ddcfc6..c117816352c7 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -430,8 +430,8 @@ axis 0x05 RZ
axis 0x06 THROTTLE
axis 0x07 RUDDER
axis 0x08 WHEEL
-axis 0x09 GAS
-axis 0x0a BRAKE
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
axis 0x10 HAT_X
axis 0x11 HAT_Y
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index a927f53e3b5f..8f32f0eab37f 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -1,4 +1,3 @@
-
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -42,8 +41,10 @@ java_test_host {
static_libs: [
"truth-prebuilt",
"kxml2-2.3.0",
+ "compile-testing-prebuilt",
"error_prone_android_framework_lib",
"error_prone_test_helpers",
+ "google_java_format",
"hamcrest-library",
"hamcrest",
"platform-test-annotations",
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java
new file mode 100644
index 000000000000..07f1d4a09006
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.LinkType.NONE;
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Description.NO_MATCH;
+import static com.google.errorprone.util.ASTHelpers.getStartPosition;
+import static com.google.errorprone.util.ASTHelpers.getSymbol;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.fixes.SuggestedFix;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.util.ASTHelpers;
+import com.google.errorprone.util.ErrorProneToken;
+import com.google.errorprone.util.ErrorProneTokens;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.tools.javac.parser.Tokens;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.lang.model.element.ElementKind;
+
+/**
+ * Bug checker to warn about {@code @hide} directives in comments.
+ *
+ * {@code @hide} tags are only meaningful inside of Javadoc comments. Errorprone has checks for
+ * standard Javadoc tags but doesn't know anything about {@code @hide} since it's an Android
+ * specific tag.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidHideInComments",
+ summary = "Warns when there are @hide declarations in comments rather than javadoc",
+ linkType = NONE,
+ severity = WARNING)
+public class HideInCommentsChecker extends BugChecker implements
+ BugChecker.CompilationUnitTreeMatcher {
+
+ @Override
+ public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
+ final Map<Integer, Tree> javadocableTrees = findJavadocableTrees(tree);
+ final String sourceCode = state.getSourceCode().toString();
+ for (ErrorProneToken token : ErrorProneTokens.getTokens(sourceCode, state.context)) {
+ for (Tokens.Comment comment : token.comments()) {
+ if (!javadocableTrees.containsKey(token.pos())) {
+ continue;
+ }
+ generateFix(comment).ifPresent(fix -> {
+ final Tree javadocableTree = javadocableTrees.get(token.pos());
+ state.reportMatch(describeMatch(javadocableTree, fix));
+ });
+ }
+ }
+ // We might have multiple matches, so report them via VisitorState rather than the return
+ // value from the match function.
+ return NO_MATCH;
+ }
+
+ private static Optional<SuggestedFix> generateFix(Tokens.Comment comment) {
+ final String text = comment.getText();
+ if (text.startsWith("/**")) {
+ return Optional.empty();
+ }
+
+ if (!text.contains("@hide")) {
+ return Optional.empty();
+ }
+
+ if (text.startsWith("/*")) {
+ final int pos = comment.getSourcePos(1);
+ return Optional.of(SuggestedFix.replace(pos, pos, "*"));
+ } else if (text.startsWith("//")) {
+ final int endPos = comment.getSourcePos(text.length() - 1);
+ final char endChar = text.charAt(text.length() - 1);
+ String javadocClose = " */";
+ if (endChar != ' ') {
+ javadocClose = endChar + javadocClose;
+ }
+ final SuggestedFix fix = SuggestedFix.builder()
+ .replace(comment.getSourcePos(1), comment.getSourcePos(2), "**")
+ .replace(endPos, endPos + 1, javadocClose)
+ .build();
+ return Optional.of(fix);
+ }
+
+ return Optional.empty();
+ }
+
+
+ private Map<Integer, Tree> findJavadocableTrees(CompilationUnitTree tree) {
+ Map<Integer, Tree> javadoccableTrees = new HashMap<>();
+ new SuppressibleTreePathScanner<Void, Void>() {
+ @Override
+ public Void visitClass(ClassTree classTree, Void unused) {
+ javadoccableTrees.put(getStartPosition(classTree), classTree);
+ return super.visitClass(classTree, null);
+ }
+
+ @Override
+ public Void visitMethod(MethodTree methodTree, Void unused) {
+ // Generated constructors never have comments
+ if (!ASTHelpers.isGeneratedConstructor(methodTree)) {
+ javadoccableTrees.put(getStartPosition(methodTree), methodTree);
+ }
+ return super.visitMethod(methodTree, null);
+ }
+
+ @Override
+ public Void visitVariable(VariableTree variableTree, Void unused) {
+ ElementKind kind = getSymbol(variableTree).getKind();
+ if (kind == ElementKind.FIELD) {
+ javadoccableTrees.put(getStartPosition(variableTree), variableTree);
+ }
+ if (kind == ElementKind.ENUM_CONSTANT) {
+ javadoccableTrees.put(getStartPosition(variableTree), variableTree);
+ if (variableTree.getInitializer() instanceof NewClassTree) {
+ // Skip the generated class definition
+ ClassTree classBody =
+ ((NewClassTree) variableTree.getInitializer()).getClassBody();
+ if (classBody != null) {
+ scan(classBody.getMembers(), null);
+ }
+ return null;
+ }
+ }
+ return super.visitVariable(variableTree, null);
+ }
+
+ }.scan(tree, null);
+ return javadoccableTrees;
+ }
+
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/HideInCommentsCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/HideInCommentsCheckerTest.java
new file mode 100644
index 000000000000..f3e6c72756e0
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/HideInCommentsCheckerTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
+
+import com.google.errorprone.BugCheckerRefactoringTestHelper;
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class HideInCommentsCheckerTest {
+ private static final String REFACTORING_FILE = "Test.java";
+
+ private BugCheckerRefactoringTestHelper mRefactoringHelper;
+ private CompilationTestHelper mCompilationHelper;
+
+ @Before
+ public void setUp() {
+ mRefactoringHelper = BugCheckerRefactoringTestHelper.newInstance(
+ HideInCommentsChecker.class, HideInCommentsCheckerTest.class);
+ mCompilationHelper = CompilationTestHelper.newInstance(
+ HideInCommentsChecker.class, HideInCommentsCheckerTest.class);
+ }
+
+
+ @Test
+ public void refactorSingleLineComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " // Foo @hide",
+ " void foo() {}",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /** Foo @hide */",
+ " void foo() {}",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorSingleLineComment_doesntAddUnnecessarySpace() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " // Foo @hide ",
+ " void foo() {}",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /** Foo @hide */",
+ " void foo() {}",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorSingleLineBlockComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /* Foo @hide */",
+ " void foo() {}",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /** Foo @hide */",
+ " void foo() {}",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorMultiLineBlockComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /*",
+ " * Foo.",
+ " *",
+ " * @hide",
+ " */",
+ " void foo(int foo) {}",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /**",
+ " * Foo.",
+ " *",
+ " * @hide",
+ " */",
+ " void foo(int foo) {}",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorFieldComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /* Foo @hide */",
+ " public int foo = 0;",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /** Foo @hide */",
+ " public int foo = 0;",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorClassComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "/* Foo @hide */",
+ "public class Test {}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "/** Foo @hide */",
+ "public class Test {}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void refactorEnumComment() {
+ mRefactoringHelper
+ .addInputLines(
+ REFACTORING_FILE,
+ "public enum Test {",
+ " /* Foo @hide */",
+ " FOO",
+ "}")
+ .addOutputLines(
+ REFACTORING_FILE,
+ "public enum Test {",
+ " /** Foo @hide */",
+ " FOO",
+ "}")
+ .doTest(TEXT_MATCH);
+ }
+
+ @Test
+ public void canBeSuppressed() {
+ mCompilationHelper
+ .addSourceLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /* Foo @hide */",
+ " @SuppressWarnings(\"AndroidHideInComments\")",
+ " void foo() {}",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void isInJavadoc() {
+ mCompilationHelper
+ .addSourceLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /** Foo @hide */",
+ " void foo() {}",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void isInMultilineJavadoc() {
+ mCompilationHelper
+ .addSourceLines(
+ REFACTORING_FILE,
+ "public class Test {",
+ " /**",
+ " * Foo.",
+ " *",
+ " * @hide",
+ " */",
+ " void foo(int foo) {}",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void noHidePresent() {
+ mCompilationHelper
+ .addSourceLines(
+ "test/" + REFACTORING_FILE,
+ "package test;",
+ "// Foo.",
+ "public class Test {",
+ " // Foo.",
+ " public int a;",
+ " /*",
+ " * Foo.",
+ " *",
+ " */",
+ " void foo(int foo) {}",
+ "}")
+ .doTest();
+ }
+
+}
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 25f76f6f6da7..2781ac4bf1da 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -36,8 +36,7 @@ public class Point implements Parcelable {
}
public Point(@NonNull Point src) {
- this.x = src.x;
- this.y = src.y;
+ set(src);
}
/**
@@ -49,6 +48,15 @@ public class Point implements Parcelable {
}
/**
+ * Sets the point's from {@code src}'s coordinates
+ * @hide
+ */
+ public void set(@NonNull Point src) {
+ this.x = src.x;
+ this.y = src.y;
+ }
+
+ /**
* Negate the point's coordinates
*/
public final void negate() {
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index abd0be9c2872..28cc05162cbb 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -497,8 +497,6 @@ public final class Font {
private static native long nBuild(
long builderPtr, @NonNull ByteBuffer buffer, @NonNull String filePath,
@NonNull String localeList, int weight, boolean italic, int ttcIndex);
- @CriticalNative
- private static native long nGetReleaseNativeFont();
@FastNative
private static native long nClone(long fontPtr, long builderPtr, int weight,
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index d083e444e996..7ad9aecaf6a3 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -89,6 +89,11 @@ public final class LineBreakConfig {
private @LineBreakWordStyle int mLineBreakWordStyle =
LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+ // Whether or not enabling phrase breaking automatically.
+ // TODO(b/226012260): Remove this and add LINE_BREAK_WORD_STYLE_PHRASE_AUTO after
+ // the experiment.
+ private boolean mAutoPhraseBreaking = false;
+
/**
* Builder constructor with line break parameters.
*/
@@ -118,12 +123,22 @@ public final class LineBreakConfig {
}
/**
+ * Enable or disable the automation of {@link LINE_BREAK_WORD_STYLE_PHRASE}.
+ *
+ * @hide
+ */
+ public @NonNull Builder setAutoPhraseBreaking(boolean autoPhraseBreaking) {
+ mAutoPhraseBreaking = autoPhraseBreaking;
+ return this;
+ }
+
+ /**
* Build the {@link LineBreakConfig}
*
* @return the LineBreakConfig instance.
*/
public @NonNull LineBreakConfig build() {
- return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle);
+ return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle, mAutoPhraseBreaking);
}
}
@@ -143,6 +158,23 @@ public final class LineBreakConfig {
.build();
}
+ /**
+ * Create the LineBreakConfig instance.
+ *
+ * @param lineBreakStyle the line break style for text wrapping.
+ * @param lineBreakWordStyle the line break word style for text wrapping.
+ * @return the {@link LineBreakConfig} instance. *
+ * @hide
+ */
+ public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
+ @LineBreakWordStyle int lineBreakWordStyle, boolean autoPhraseBreaking) {
+ LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
+ return builder.setLineBreakStyle(lineBreakStyle)
+ .setLineBreakWordStyle(lineBreakWordStyle)
+ .setAutoPhraseBreaking(autoPhraseBreaking)
+ .build();
+ }
+
/** @hide */
public static final LineBreakConfig NONE =
new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
@@ -150,15 +182,17 @@ public final class LineBreakConfig {
private final @LineBreakStyle int mLineBreakStyle;
private final @LineBreakWordStyle int mLineBreakWordStyle;
+ private final boolean mAutoPhraseBreaking;
/**
* Constructor with the line break parameters.
* Use the {@link LineBreakConfig.Builder} to create the LineBreakConfig instance.
*/
private LineBreakConfig(@LineBreakStyle int lineBreakStyle,
- @LineBreakWordStyle int lineBreakWordStyle) {
+ @LineBreakWordStyle int lineBreakWordStyle, boolean autoPhraseBreaking) {
mLineBreakStyle = lineBreakStyle;
mLineBreakWordStyle = lineBreakWordStyle;
+ mAutoPhraseBreaking = autoPhraseBreaking;
}
/**
@@ -179,6 +213,17 @@ public final class LineBreakConfig {
return mLineBreakWordStyle;
}
+ /**
+ * Used to identify if the automation of {@link LINE_BREAK_WORD_STYLE_PHRASE} is enabled.
+ *
+ * @return The result that records whether or not the automation of
+ * {@link LINE_BREAK_WORD_STYLE_PHRASE} is enabled.
+ * @hide
+ */
+ public boolean getAutoPhraseBreaking() {
+ return mAutoPhraseBreaking;
+ }
+
@Override
public boolean equals(Object o) {
if (o == null) return false;
@@ -186,7 +231,8 @@ public final class LineBreakConfig {
if (!(o instanceof LineBreakConfig)) return false;
LineBreakConfig that = (LineBreakConfig) o;
return (mLineBreakStyle == that.mLineBreakStyle)
- && (mLineBreakWordStyle == that.mLineBreakWordStyle);
+ && (mLineBreakWordStyle == that.mLineBreakWordStyle)
+ && (mAutoPhraseBreaking == that.mAutoPhraseBreaking);
}
@Override
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index 8e011053d2a7..c591c879059c 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -38,8 +38,9 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import javax.crypto.BadPaddingException;
@@ -227,7 +228,7 @@ class CredstoreIdentityCredential extends IdentityCredential {
throw new RuntimeException("Error decoding certificates", e);
}
- LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ ArrayList<X509Certificate> x509Certs = new ArrayList<>();
for (Certificate cert : certs) {
x509Certs.add((X509Certificate) cert);
}
@@ -384,7 +385,7 @@ class CredstoreIdentityCredential extends IdentityCredential {
public @NonNull Collection<X509Certificate> getAuthKeysNeedingCertification() {
try {
AuthKeyParcel[] authKeyParcels = mBinder.getAuthKeysNeedingCertification();
- LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ ArrayList<X509Certificate> x509Certs = new ArrayList<>();
CertificateFactory factory = CertificateFactory.getInstance("X.509");
for (AuthKeyParcel authKeyParcel : authKeyParcels) {
Collection<? extends Certificate> certs = null;
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
index d2e7984ce19f..1ad70edb7c6f 100644
--- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -25,8 +25,9 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.LinkedList;
+import java.util.List;
class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
@@ -61,7 +62,7 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
throw new RuntimeException("Error decoding certificates", e);
}
- LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ ArrayList<X509Certificate> x509Certs = new ArrayList<>();
for (Certificate cert : certs) {
x509Certs.add((X509Certificate) cert);
}
diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java
index b34f2505a6a6..bdb00fdfb341 100644
--- a/identity/java/android/security/identity/PersonalizationData.java
+++ b/identity/java/android/security/identity/PersonalizationData.java
@@ -18,10 +18,11 @@ package android.security.identity;
import android.annotation.NonNull;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
+import java.util.List;
/**
* An object that holds personalization data.
@@ -38,7 +39,7 @@ public class PersonalizationData {
private PersonalizationData() {
}
- private LinkedList<AccessControlProfile> mProfiles = new LinkedList<>();
+ private ArrayList<AccessControlProfile> mProfiles = new ArrayList<>();
private LinkedHashMap<String, NamespaceData> mNamespaces = new LinkedHashMap<>();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index 921552b6cfbb..68ff806c6765 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -199,7 +199,7 @@ public final class CommonFoldingFeature {
throw new IllegalArgumentException(
"Display feature rectangle cannot have zero width and height simultaneously.");
}
- this.mRect = rect;
+ this.mRect = new Rect(rect);
}
/** Returns the type of the feature. */
@@ -217,7 +217,7 @@ public final class CommonFoldingFeature {
/** Returns the bounds of the feature. */
@NonNull
public Rect getRect() {
- return mRect;
+ return new Rect(mRect);
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index fdcb7be597d5..cc2bb63ca8e1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -22,7 +22,6 @@ import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
import static androidx.window.common.CommonFoldingFeature.parseListFromString;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
@@ -30,22 +29,25 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
+import androidx.window.util.AcceptOnceConsumer;
import androidx.window.util.BaseDataProducer;
-import androidx.window.util.DataProducer;
import com.android.internal.R;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
/**
- * An implementation of {@link androidx.window.util.DataProducer} that returns the device's posture
- * by mapping the state returned from {@link DeviceStateManager} to values provided in the resources
- * config at {@link R.array#config_device_state_postures}.
+ * An implementation of {@link androidx.window.util.BaseDataProducer} that returns
+ * the device's posture by mapping the state returned from {@link DeviceStateManager} to
+ * values provided in the resources' config at {@link R.array#config_device_state_postures}.
*/
-public final class DeviceStateManagerFoldingFeatureProducer extends
- BaseDataProducer<List<CommonFoldingFeature>> {
+public final class DeviceStateManagerFoldingFeatureProducer
+ extends BaseDataProducer<List<CommonFoldingFeature>> {
private static final String TAG =
DeviceStateManagerFoldingFeatureProducer.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -54,15 +56,11 @@ public final class DeviceStateManagerFoldingFeatureProducer extends
private int mCurrentDeviceState = INVALID_DEVICE_STATE;
- private final DeviceStateCallback mDeviceStateCallback = (state) -> {
- mCurrentDeviceState = state;
- notifyDataChanged();
- };
@NonNull
- private final DataProducer<String> mRawFoldSupplier;
+ private final BaseDataProducer<String> mRawFoldSupplier;
public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
- @NonNull DataProducer<String> rawFoldSupplier) {
+ @NonNull BaseDataProducer<String> rawFoldSupplier) {
mRawFoldSupplier = rawFoldSupplier;
String[] deviceStatePosturePairs = context.getResources()
.getStringArray(R.array.config_device_state_postures);
@@ -70,7 +68,8 @@ public final class DeviceStateManagerFoldingFeatureProducer extends
String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
if (deviceStatePostureMapping.length != 2) {
if (DEBUG) {
- Log.e(TAG, "Malformed device state posture pair: " + deviceStatePosturePair);
+ Log.e(TAG, "Malformed device state posture pair: "
+ + deviceStatePosturePair);
}
continue;
}
@@ -82,7 +81,8 @@ public final class DeviceStateManagerFoldingFeatureProducer extends
posture = Integer.parseInt(deviceStatePostureMapping[1]);
} catch (NumberFormatException e) {
if (DEBUG) {
- Log.e(TAG, "Failed to parse device state or posture: " + deviceStatePosturePair,
+ Log.e(TAG, "Failed to parse device state or posture: "
+ + deviceStatePosturePair,
e);
}
continue;
@@ -92,32 +92,95 @@ public final class DeviceStateManagerFoldingFeatureProducer extends
}
if (mDeviceStateToPostureMap.size() > 0) {
- context.getSystemService(DeviceStateManager.class)
- .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
+ DeviceStateCallback deviceStateCallback = (state) -> {
+ mCurrentDeviceState = state;
+ mRawFoldSupplier.getData(this::notifyFoldingFeatureChange);
+ };
+ Objects.requireNonNull(context.getSystemService(DeviceStateManager.class))
+ .registerCallback(context.getMainExecutor(), deviceStateCallback);
}
}
- @Override
- @Nullable
- public Optional<List<CommonFoldingFeature>> getData() {
- final int globalHingeState = globalHingeState();
- Optional<String> displayFeaturesString = mRawFoldSupplier.getData();
- if (displayFeaturesString.isEmpty() || TextUtils.isEmpty(displayFeaturesString.get())) {
- return Optional.empty();
+ /**
+ * Add a callback to mCallbacks if there is no device state. This callback will be run
+ * once a device state is set. Otherwise,run the callback immediately.
+ */
+ private void runCallbackWhenValidState(@NonNull Consumer<List<CommonFoldingFeature>> callback,
+ String displayFeaturesString) {
+ if (isCurrentStateValid()) {
+ callback.accept(calculateFoldingFeature(displayFeaturesString));
+ } else {
+ // This callback will be added to mCallbacks and removed once it runs once.
+ AcceptOnceConsumer<List<CommonFoldingFeature>> singleRunCallback =
+ new AcceptOnceConsumer<>(this, callback);
+ addDataChangedCallback(singleRunCallback);
}
- return Optional.of(parseListFromString(displayFeaturesString.get(), globalHingeState));
+ }
+
+ /**
+ * Checks to find {@link DeviceStateManagerFoldingFeatureProducer#mCurrentDeviceState} in the
+ * {@link DeviceStateManagerFoldingFeatureProducer#mDeviceStateToPostureMap} which was
+ * initialized in the constructor of {@link DeviceStateManagerFoldingFeatureProducer}.
+ * Returns a boolean value of whether the device state is valid.
+ */
+ private boolean isCurrentStateValid() {
+ // If the device state is not found in the map, indexOfKey returns a negative number.
+ return mDeviceStateToPostureMap.indexOfKey(mCurrentDeviceState) >= 0;
}
@Override
- protected void onListenersChanged(Set<Runnable> callbacks) {
+ protected void onListenersChanged(
+ @NonNull Set<Consumer<List<CommonFoldingFeature>>> callbacks) {
super.onListenersChanged(callbacks);
if (callbacks.isEmpty()) {
- mRawFoldSupplier.removeDataChangedCallback(this::notifyDataChanged);
+ mCurrentDeviceState = INVALID_DEVICE_STATE;
+ mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChange);
+ } else {
+ mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChange);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Optional<List<CommonFoldingFeature>> getCurrentData() {
+ Optional<String> displayFeaturesString = mRawFoldSupplier.getCurrentData();
+ if (!isCurrentStateValid()) {
+ return Optional.empty();
+ } else {
+ return displayFeaturesString.map(this::calculateFoldingFeature);
+ }
+ }
+
+ /**
+ * Adds the data to the storeFeaturesConsumer when the data is ready.
+ * @param storeFeaturesConsumer a consumer to collect the data when it is first available.
+ */
+ public void getData(Consumer<List<CommonFoldingFeature>> storeFeaturesConsumer) {
+ mRawFoldSupplier.getData((String displayFeaturesString) -> {
+ if (TextUtils.isEmpty(displayFeaturesString)) {
+ storeFeaturesConsumer.accept(new ArrayList<>());
+ } else {
+ runCallbackWhenValidState(storeFeaturesConsumer, displayFeaturesString);
+ }
+ });
+ }
+
+ private void notifyFoldingFeatureChange(String displayFeaturesString) {
+ if (!isCurrentStateValid()) {
+ return;
+ }
+ if (TextUtils.isEmpty(displayFeaturesString)) {
+ notifyDataChanged(new ArrayList<>());
} else {
- mRawFoldSupplier.addDataChangedCallback(this::notifyDataChanged);
+ notifyDataChanged(calculateFoldingFeature(displayFeaturesString));
}
}
+ private List<CommonFoldingFeature> calculateFoldingFeature(String displayFeaturesString) {
+ final int globalHingeState = globalHingeState();
+ return parseListFromString(displayFeaturesString, globalHingeState);
+ }
+
private int globalHingeState() {
return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java
index 69ad1badce60..7906342d445d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java
@@ -32,6 +32,7 @@ import com.android.internal.R;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Implementation of {@link androidx.window.util.DataProducer} that produces a
@@ -40,7 +41,7 @@ import java.util.Set;
* settings where the {@link String} property is saved with the key
* {@link RawFoldingFeatureProducer#DISPLAY_FEATURES}. If this value is null or empty then the
* value in {@link android.content.res.Resources} is used. If both are empty then
- * {@link RawFoldingFeatureProducer#getData()} returns an empty object.
+ * {@link RawFoldingFeatureProducer#getData} returns an empty object.
* {@link RawFoldingFeatureProducer} listens to changes in the setting so that it can override
* the system {@link CommonFoldingFeature} data.
*/
@@ -63,12 +64,13 @@ public final class RawFoldingFeatureProducer extends BaseDataProducer<String> {
@Override
@NonNull
- public Optional<String> getData() {
+ public void getData(Consumer<String> dataConsumer) {
String displayFeaturesString = getFeatureString();
if (displayFeaturesString == null) {
- return Optional.empty();
+ dataConsumer.accept("");
+ } else {
+ dataConsumer.accept(displayFeaturesString);
}
- return Optional.of(displayFeaturesString);
}
/**
@@ -84,7 +86,7 @@ public final class RawFoldingFeatureProducer extends BaseDataProducer<String> {
}
@Override
- protected void onListenersChanged(Set<Runnable> callbacks) {
+ protected void onListenersChanged(Set<Consumer<String>> callbacks) {
if (callbacks.isEmpty()) {
unregisterObserversIfNeeded();
} else {
@@ -92,6 +94,12 @@ public final class RawFoldingFeatureProducer extends BaseDataProducer<String> {
}
}
+ @NonNull
+ @Override
+ public Optional<String> getCurrentData() {
+ return Optional.of(getFeatureString());
+ }
+
/**
* Registers settings observers, if needed. When settings observers are registered for this
* producer callbacks for changes in data will be triggered.
@@ -125,8 +133,8 @@ public final class RawFoldingFeatureProducer extends BaseDataProducer<String> {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mDisplayFeaturesUri.equals(uri)) {
- notifyDataChanged();
+ notifyDataChanged(getFeatureString());
}
}
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 44af1a9fd780..f09a91018bf0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;
import android.annotation.NonNull;
import android.app.Activity;
+import android.util.Pair;
+import android.util.Size;
/**
* Client-side descriptor of a split that holds two containers.
@@ -66,6 +68,13 @@ class SplitContainer {
return mSplitRule;
}
+ /** Returns the minimum dimension pair of primary container and secondary container. */
+ @NonNull
+ Pair<Size, Size> getMinDimensionsPair() {
+ return new Pair<>(mPrimaryContainer.getMinDimensions(),
+ mSecondaryContainer.getMinDimensions());
+ }
+
boolean isPlaceholderContainer() {
return (mSplitRule instanceof SplitPlaceholderRule);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 575c3f002791..242e9ab6beee 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -24,9 +24,11 @@ import static androidx.window.extensions.embedding.SplitContainer.getFinishSecon
import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
+import static androidx.window.extensions.embedding.SplitPresenter.boundsSmallerThanMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
+import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityOptions;
@@ -43,11 +45,15 @@ import android.os.IBinder;
import android.os.Looper;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import com.android.internal.annotations.VisibleForTesting;
@@ -63,7 +69,7 @@ import java.util.function.Consumer;
*/
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent {
- private static final String TAG = "SplitController";
+ static final String TAG = "SplitController";
@VisibleForTesting
@GuardedBy("mLock")
@@ -350,7 +356,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (!(rule instanceof SplitRule)) {
continue;
}
- if (mPresenter.shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
+ if (shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
return true;
}
}
@@ -610,11 +616,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
primaryActivity);
final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
- && canReuseContainer(splitRule, splitContainer.getSplitRule())) {
+ && canReuseContainer(splitRule, splitContainer.getSplitRule())
+ && !boundsSmallerThanMinDimensions(primaryContainer.getLastRequestedBounds(),
+ getMinDimensions(primaryActivity))) {
// Can launch in the existing secondary container if the rules share the same
// presentation.
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
- if (secondaryContainer == getContainerWithActivity(secondaryActivity)) {
+ if (secondaryContainer == getContainerWithActivity(secondaryActivity)
+ && !boundsSmallerThanMinDimensions(secondaryContainer.getLastRequestedBounds(),
+ getMinDimensions(secondaryActivity))) {
// The activity is already in the target TaskFragment.
return true;
}
@@ -791,9 +801,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
&& (canReuseContainer(splitRule, splitContainer.getSplitRule())
// TODO(b/231845476) we should always respect clearTop.
|| !respectClearTop)) {
- // Can launch in the existing secondary container if the rules share the same
- // presentation.
- return splitContainer.getSecondaryContainer();
+ final Rect secondaryBounds = splitContainer.getSecondaryContainer()
+ .getLastRequestedBounds();
+ if (secondaryBounds.isEmpty()
+ || !boundsSmallerThanMinDimensions(secondaryBounds,
+ getMinDimensions(intent))) {
+ // Can launch in the existing secondary container if the rules share the same
+ // presentation.
+ return splitContainer.getSecondaryContainer();
+ }
}
// Create a new TaskFragment to split with the primary activity for the new activity.
return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent,
@@ -1117,8 +1133,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Check if there is enough space for launch
final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
- if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
- mPresenter.getParentContainerBounds(activity), placeholderRule)) {
+
+ if (placeholderRule == null) {
+ return false;
+ }
+
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(activity,
+ placeholderRule.getPlaceholderIntent());
+ if (!shouldShowSideBySide(
+ mPresenter.getParentContainerBounds(activity), placeholderRule,
+ minDimensionsPair)) {
return false;
}
@@ -1161,7 +1185,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
- if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ if (shouldShowSideBySide(splitContainer)) {
return false;
}
@@ -1233,7 +1257,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Splits that are not showing side-by-side are reported as having 0 split
// ratio, since by definition in the API the primary container occupies no
// width of the split when covered by the secondary.
- mPresenter.shouldShowSideBySide(container)
+ shouldShowSideBySide(container)
? container.getSplitRule().getSplitRatio()
: 0.0f);
splitStates.add(splitState);
@@ -1402,7 +1426,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
// Decide whether the associated container should be retained based on the current
// presentation mode.
- if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ if (shouldShowSideBySide(splitContainer)) {
return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
} else {
return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index ac3b05a0e825..1b79ad999435 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -16,15 +16,23 @@
package androidx.window.extensions.embedding;
+import static android.content.pm.PackageManager.MATCH_ALL;
+
import android.app.Activity;
+import android.app.ActivityThread;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.util.LayoutDirection;
+import android.util.Pair;
+import android.util.Size;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowMetrics;
@@ -34,6 +42,8 @@ import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.concurrent.Executor;
/**
@@ -41,9 +51,12 @@ import java.util.concurrent.Executor;
* {@link SplitController}.
*/
class SplitPresenter extends JetpackTaskFragmentOrganizer {
- private static final int POSITION_START = 0;
- private static final int POSITION_END = 1;
- private static final int POSITION_FILL = 2;
+ @VisibleForTesting
+ static final int POSITION_START = 0;
+ @VisibleForTesting
+ static final int POSITION_END = 1;
+ @VisibleForTesting
+ static final int POSITION_FILL = 2;
@IntDef(value = {
POSITION_START,
@@ -103,8 +116,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
@NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
@NonNull Intent secondaryIntent, @NonNull SplitPairRule rule) {
final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(
+ primaryActivity, secondaryIntent);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
primaryActivity, primaryRectBounds, null);
@@ -113,7 +128,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final TaskFragmentContainer secondaryContainer = mController.newContainer(
secondaryIntent, primaryActivity, taskId);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
- rule, isLtr(primaryActivity, rule));
+ rule, primaryActivity, minDimensionsPair);
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(secondaryRectBounds);
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
@@ -121,7 +136,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
windowingMode);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -144,13 +160,15 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivitiesMinDimensionsPair(primaryActivity,
+ secondaryActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
primaryActivity, primaryRectBounds, null);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer curSecondaryContainer = mController.getContainerWithActivity(
secondaryActivity);
TaskFragmentContainer containerToAvoid = primaryContainer;
@@ -162,7 +180,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
secondaryActivity, secondaryRectBounds, containerToAvoid);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -211,10 +230,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
@Nullable Bundle activityOptions, @NonNull SplitRule rule, boolean isPlaceholder) {
final Rect parentBounds = getParentContainerBounds(launchingActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(
+ launchingActivity, activityIntent);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(launchingActivity, rule));
+ launchingActivity, minDimensionsPair);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr(launchingActivity, rule));
+ launchingActivity, minDimensionsPair);
TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
launchingActivity);
@@ -258,11 +279,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
if (activity == null) {
return;
}
- final boolean isLtr = isLtr(activity, rule);
+ final Pair<Size, Size> minDimensionsPair = splitContainer.getMinDimensionsPair();
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr);
+ activity, minDimensionsPair);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr);
+ activity, minDimensionsPair);
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
// Whether the placeholder is becoming side-by-side with the primary from fullscreen.
final boolean isPlaceholderBecomingSplit = splitContainer.isPlaceholderContainer()
@@ -273,7 +294,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
// are created again.
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
if (isPlaceholderBecomingSplit) {
// When placeholder is shown in split, we should keep the focus on the primary.
wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
@@ -287,11 +309,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer primaryContainer,
- @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule splitRule) {
+ @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule splitRule,
+ @NonNull Pair<Size, Size> minDimensionsPair) {
final Rect parentBounds = getParentContainerBounds(primaryContainer);
// Clear adjacent TaskFragments if the container is shown in fullscreen, or the
// secondaryContainer could not be finished.
- if (!shouldShowSideBySide(parentBounds, splitRule)) {
+ if (!shouldShowSideBySide(parentBounds, splitRule, minDimensionsPair)) {
setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
null /* secondary */, null /* splitRule */);
} else {
@@ -373,41 +396,132 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
super.updateWindowingMode(wct, fragmentToken, windowingMode);
}
- boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
+ static boolean shouldShowSideBySide(@NonNull Rect parentBounds, @NonNull SplitRule rule) {
+ return shouldShowSideBySide(parentBounds, rule, null /* minimumDimensionPair */);
+ }
+
+ static boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
- return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule());
+
+ return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule(),
+ splitContainer.getMinDimensionsPair());
}
- boolean shouldShowSideBySide(@Nullable Rect parentBounds, @NonNull SplitRule rule) {
+ static boolean shouldShowSideBySide(@NonNull Rect parentBounds, @NonNull SplitRule rule,
+ @Nullable Pair<Size, Size> minDimensionsPair) {
// TODO(b/190433398): Supply correct insets.
final WindowMetrics parentMetrics = new WindowMetrics(parentBounds,
new WindowInsets(new Rect()));
- return rule.checkParentMetrics(parentMetrics);
+ // Don't show side by side if bounds is not qualified.
+ if (!rule.checkParentMetrics(parentMetrics)) {
+ return false;
+ }
+ final float splitRatio = rule.getSplitRatio();
+ // We only care the size of the bounds regardless of its position.
+ final Rect primaryBounds = getPrimaryBounds(parentBounds, splitRatio, true /* isLtr */);
+ final Rect secondaryBounds = getSecondaryBounds(parentBounds, splitRatio, true /* isLtr */);
+
+ if (minDimensionsPair == null) {
+ return true;
+ }
+ return !boundsSmallerThanMinDimensions(primaryBounds, minDimensionsPair.first)
+ && !boundsSmallerThanMinDimensions(secondaryBounds, minDimensionsPair.second);
}
@NonNull
- private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
- @NonNull SplitRule rule, boolean isLtr) {
- if (!shouldShowSideBySide(parentBounds, rule)) {
- return new Rect();
+ static Pair<Size, Size> getActivitiesMinDimensionsPair(Activity primaryActivity,
+ Activity secondaryActivity) {
+ return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryActivity));
+ }
+
+ @NonNull
+ static Pair<Size, Size> getActivityIntentMinDimensionsPair(Activity primaryActivity,
+ Intent secondaryIntent) {
+ return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryIntent));
+ }
+
+ @Nullable
+ static Size getMinDimensions(@Nullable Activity activity) {
+ if (activity == null) {
+ return null;
+ }
+ final ActivityInfo.WindowLayout windowLayout = activity.getActivityInfo().windowLayout;
+ if (windowLayout == null) {
+ return null;
}
+ return new Size(windowLayout.minWidth, windowLayout.minHeight);
+ }
+ // TODO(b/232871351): find a light-weight approach for this check.
+ @Nullable
+ static Size getMinDimensions(@Nullable Intent intent) {
+ if (intent == null) {
+ return null;
+ }
+ final PackageManager packageManager = ActivityThread.currentActivityThread()
+ .getApplication().getPackageManager();
+ final ResolveInfo resolveInfo = packageManager.resolveActivity(intent,
+ PackageManager.ResolveInfoFlags.of(MATCH_ALL));
+ if (resolveInfo == null) {
+ return null;
+ }
+ final ActivityInfo activityInfo = resolveInfo.activityInfo;
+ if (activityInfo == null) {
+ return null;
+ }
+ final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout;
+ if (windowLayout == null) {
+ return null;
+ }
+ return new Size(windowLayout.minWidth, windowLayout.minHeight);
+ }
+
+ static boolean boundsSmallerThanMinDimensions(@NonNull Rect bounds,
+ @Nullable Size minDimensions) {
+ if (minDimensions == null) {
+ return false;
+ }
+ return bounds.width() < minDimensions.getWidth()
+ || bounds.height() < minDimensions.getHeight();
+ }
+
+ @VisibleForTesting
+ @NonNull
+ static Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
+ @NonNull SplitRule rule, @NonNull Activity primaryActivity,
+ @Nullable Pair<Size, Size> minDimensionsPair) {
+ if (!shouldShowSideBySide(parentBounds, rule, minDimensionsPair)) {
+ return new Rect();
+ }
+ final boolean isLtr = isLtr(primaryActivity, rule);
final float splitRatio = rule.getSplitRatio();
- final float rtlSplitRatio = 1 - splitRatio;
+
switch (position) {
case POSITION_START:
- return isLtr ? getLeftContainerBounds(parentBounds, splitRatio)
- : getRightContainerBounds(parentBounds, rtlSplitRatio);
+ return getPrimaryBounds(parentBounds, splitRatio, isLtr);
case POSITION_END:
- return isLtr ? getRightContainerBounds(parentBounds, splitRatio)
- : getLeftContainerBounds(parentBounds, rtlSplitRatio);
+ return getSecondaryBounds(parentBounds, splitRatio, isLtr);
case POSITION_FILL:
- return parentBounds;
+ default:
+ return new Rect();
}
- return parentBounds;
}
- private Rect getLeftContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+ @NonNull
+ private static Rect getPrimaryBounds(@NonNull Rect parentBounds, float splitRatio,
+ boolean isLtr) {
+ return isLtr ? getLeftContainerBounds(parentBounds, splitRatio)
+ : getRightContainerBounds(parentBounds, 1 - splitRatio);
+ }
+
+ @NonNull
+ private static Rect getSecondaryBounds(@NonNull Rect parentBounds, float splitRatio,
+ boolean isLtr) {
+ return isLtr ? getRightContainerBounds(parentBounds, splitRatio)
+ : getLeftContainerBounds(parentBounds, 1 - splitRatio);
+ }
+
+ private static Rect getLeftContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
return new Rect(
parentBounds.left,
parentBounds.top,
@@ -415,7 +529,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
parentBounds.bottom);
}
- private Rect getRightContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+ private static Rect getRightContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
return new Rect(
(int) (parentBounds.left + parentBounds.width() * splitRatio),
parentBounds.top,
@@ -427,7 +541,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
* Checks if a split with the provided rule should be displays in left-to-right layout
* direction, either always or with the current configuration.
*/
- private boolean isLtr(@NonNull Context context, @NonNull SplitRule rule) {
+ private static boolean isLtr(@NonNull Context context, @NonNull SplitRule rule) {
switch (rule.getLayoutDirection()) {
case LayoutDirection.LOCALE:
return context.getResources().getConfiguration().getLayoutDirection()
@@ -441,7 +555,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
}
@NonNull
- Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
+ static Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
return container.getTaskContainer().getTaskBounds();
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 624cde50ff72..abf32a26efa2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.util.Size;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -414,6 +415,11 @@ class TaskFragmentContainer {
}
}
+ @NonNull
+ Rect getLastRequestedBounds() {
+ return mLastRequestedBounds;
+ }
+
/**
* Checks if last requested windowing mode is equal to the provided value.
*/
@@ -439,6 +445,31 @@ class TaskFragmentContainer {
return mTaskContainer;
}
+ @Nullable
+ Size getMinDimensions() {
+ if (mInfo == null) {
+ return null;
+ }
+ int maxMinWidth = mInfo.getMinimumWidth();
+ int maxMinHeight = mInfo.getMinimumHeight();
+ for (Activity activity : mPendingAppearedActivities) {
+ final Size minDimensions = SplitPresenter.getMinDimensions(activity);
+ if (minDimensions == null) {
+ continue;
+ }
+ maxMinWidth = Math.max(maxMinWidth, minDimensions.getWidth());
+ maxMinHeight = Math.max(maxMinHeight, minDimensions.getHeight());
+ }
+ if (mPendingAppearedIntent != null) {
+ final Size minDimensions = SplitPresenter.getMinDimensions(mPendingAppearedIntent);
+ if (minDimensions != null) {
+ maxMinWidth = Math.max(maxMinWidth, minDimensions.getWidth());
+ maxMinHeight = Math.max(maxMinHeight, minDimensions.getHeight());
+ }
+ }
+ return new Size(maxMinWidth, maxMinHeight);
+ }
+
@Override
public String toString() {
return toString(true /* includeContainersToFinishOnExit */);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index a6f638822d10..cfb32050e32f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -43,7 +43,6 @@ import androidx.window.util.DataProducer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@@ -63,7 +62,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
- public WindowLayoutComponentImpl(Context context) {
+ public WindowLayoutComponentImpl(@NonNull Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
RawFoldingFeatureProducer foldingFeatureProducer = new RawFoldingFeatureProducer(context);
@@ -80,8 +79,12 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
*/
public void addWindowLayoutInfoListener(@NonNull Activity activity,
@NonNull Consumer<WindowLayoutInfo> consumer) {
+ mFoldingFeatureProducer.getData((features) -> {
+ // Get the WindowLayoutInfo from the activity and pass the value to the layoutConsumer.
+ WindowLayoutInfo newWindowLayout = getWindowLayoutInfo(activity, features);
+ consumer.accept(newWindowLayout);
+ });
mWindowLayoutChangeListeners.put(activity, consumer);
- onDisplayFeaturesChanged();
}
/**
@@ -89,18 +92,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
*
* @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
*/
- public void removeWindowLayoutInfoListener(
- @NonNull Consumer<WindowLayoutInfo> consumer) {
+ public void removeWindowLayoutInfoListener(@NonNull Consumer<WindowLayoutInfo> consumer) {
mWindowLayoutChangeListeners.values().remove(consumer);
- onDisplayFeaturesChanged();
- }
-
- void updateWindowLayout(@NonNull Activity activity,
- @NonNull WindowLayoutInfo newLayout) {
- Consumer<WindowLayoutInfo> consumer = mWindowLayoutChangeListeners.get(activity);
- if (consumer != null) {
- consumer.accept(newLayout);
- }
}
@NonNull
@@ -108,7 +101,6 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
return mWindowLayoutChangeListeners.keySet();
}
- @NonNull
private boolean isListeningForLayoutChanges(IBinder token) {
for (Activity activity: getActivitiesListeningForLayoutChanges()) {
if (token.equals(activity.getWindow().getAttributes().token)) {
@@ -125,12 +117,12 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
/**
* A convenience method to translate from the common feature state to the extensions feature
* state. More specifically, translates from {@link CommonFoldingFeature.State} to
- * {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not
+ * {@link FoldingFeature#STATE_FLAT} or {@link FoldingFeature#STATE_HALF_OPENED}. If it is not
* possible to translate, then we will return a {@code null} value.
*
* @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
- * otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
- * {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
+ * otherwise. @return a {@link FoldingFeature#STATE_FLAT} or
+ * {@link FoldingFeature#STATE_HALF_OPENED} if the given state matches a value in
* {@link CommonFoldingFeature.State} and {@code null} otherwise.
*/
@Nullable
@@ -144,17 +136,24 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
}
}
- private void onDisplayFeaturesChanged() {
+ private void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
for (Activity activity : getActivitiesListeningForLayoutChanges()) {
- WindowLayoutInfo newLayout = getWindowLayoutInfo(activity);
- updateWindowLayout(activity, newLayout);
+ // Get the WindowLayoutInfo from the activity and pass the value to the layoutConsumer.
+ Consumer<WindowLayoutInfo> layoutConsumer = mWindowLayoutChangeListeners.get(activity);
+ WindowLayoutInfo newWindowLayout = getWindowLayoutInfo(activity, storedFeatures);
+ layoutConsumer.accept(newWindowLayout);
}
}
- @NonNull
- private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
- List<DisplayFeature> displayFeatures = getDisplayFeatures(activity);
- return new WindowLayoutInfo(displayFeatures);
+ /**
+ * Translates the {@link DisplayFeature} into a {@link WindowLayoutInfo} when a
+ * valid state is found.
+ * @param activity a proxy for the {@link android.view.Window} that contains the
+ */
+ private WindowLayoutInfo getWindowLayoutInfo(
+ @NonNull Activity activity, List<CommonFoldingFeature> storedFeatures) {
+ List<DisplayFeature> displayFeatureList = getDisplayFeatures(activity, storedFeatures);
+ return new WindowLayoutInfo(displayFeatureList);
}
/**
@@ -172,26 +171,21 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
*
* @param activity a proxy for the {@link android.view.Window} that contains the
* {@link DisplayFeature}.
- * @return a {@link List} of valid {@link DisplayFeature} that
* are within the {@link android.view.Window} of the {@link Activity}
*/
- private List<DisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
+ private List<DisplayFeature> getDisplayFeatures(
+ @NonNull Activity activity, List<CommonFoldingFeature> storedFeatures) {
List<DisplayFeature> features = new ArrayList<>();
int displayId = activity.getDisplay().getDisplayId();
if (displayId != DEFAULT_DISPLAY) {
Log.w(TAG, "This sample doesn't support display features on secondary displays");
return features;
- }
-
- if (activity.isInMultiWindowMode()) {
+ } else if (activity.isInMultiWindowMode()) {
// It is recommended not to report any display features in multi-window mode, since it
// won't be possible to synchronize the display feature positions with window movement.
return features;
- }
-
- Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
- if (storedFeatures.isPresent()) {
- for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
+ } else {
+ for (CommonFoldingFeature baseFeature : storedFeatures) {
Integer state = convertToExtensionState(baseFeature.getState());
if (state == null) {
continue;
@@ -205,8 +199,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
features.add(new FoldingFeature(featureRect, baseFeature.getType(), state));
}
}
+ return features;
}
- return features;
}
/**
@@ -233,7 +227,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private void onDisplayFeaturesChangedIfListening(Activity activity) {
IBinder token = activity.getWindow().getAttributes().token;
if (token == null || isListeningForLayoutChanges(token)) {
- onDisplayFeaturesChanged();
+ mFoldingFeatureProducer.getData(
+ WindowLayoutComponentImpl.this::onDisplayFeaturesChanged);
}
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index 970f0a2af632..5bfb0ebdcaa8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -28,41 +28,42 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.RawFoldingFeatureProducer;
-import androidx.window.util.DataProducer;
+import androidx.window.util.BaseDataProducer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
/**
* Reference implementation of androidx.window.sidecar OEM interface for use with
* WindowManager Jetpack.
*/
class SampleSidecarImpl extends StubSidecar {
- private static final String TAG = "SampleSidecar";
-
- private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
-
+ private List<CommonFoldingFeature> mStoredFeatures = new ArrayList<>();
SampleSidecarImpl(Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
- DataProducer<String> settingsFeatureProducer = new RawFoldingFeatureProducer(context);
- mFoldingFeatureProducer = new DeviceStateManagerFoldingFeatureProducer(context,
- settingsFeatureProducer);
+ BaseDataProducer<String> settingsFeatureProducer = new RawFoldingFeatureProducer(context);
+ BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer =
+ new DeviceStateManagerFoldingFeatureProducer(context,
+ settingsFeatureProducer);
- mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
+ foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
- private void onDisplayFeaturesChanged() {
+ private void setStoredFeatures(List<CommonFoldingFeature> storedFeatures) {
+ mStoredFeatures = storedFeatures;
+ }
+
+ private void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
+ setStoredFeatures(storedFeatures);
updateDeviceState(getDeviceState());
for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
@@ -79,16 +80,16 @@ class SampleSidecarImpl extends StubSidecar {
}
private int deviceStateFromFeature() {
- List<CommonFoldingFeature> storedFeatures = mFoldingFeatureProducer.getData()
- .orElse(Collections.emptyList());
- for (int i = 0; i < storedFeatures.size(); i++) {
- CommonFoldingFeature feature = storedFeatures.get(i);
+ for (int i = 0; i < mStoredFeatures.size(); i++) {
+ CommonFoldingFeature feature = mStoredFeatures.get(i);
final int state = feature.getState();
switch (state) {
case CommonFoldingFeature.COMMON_STATE_FLAT:
return SidecarDeviceState.POSTURE_OPENED;
case CommonFoldingFeature.COMMON_STATE_HALF_OPENED:
return SidecarDeviceState.POSTURE_HALF_OPENED;
+ case CommonFoldingFeature.COMMON_STATE_UNKNOWN:
+ return SidecarDeviceState.POSTURE_UNKNOWN;
}
}
return SidecarDeviceState.POSTURE_UNKNOWN;
@@ -109,7 +110,6 @@ class SampleSidecarImpl extends StubSidecar {
private List<SidecarDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
int displayId = activity.getDisplay().getDisplayId();
if (displayId != DEFAULT_DISPLAY) {
- Log.w(TAG, "This sample doesn't support display features on secondary displays");
return Collections.emptyList();
}
@@ -119,18 +119,15 @@ class SampleSidecarImpl extends StubSidecar {
return Collections.emptyList();
}
- Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
List<SidecarDisplayFeature> features = new ArrayList<>();
- if (storedFeatures.isPresent()) {
- for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
- SidecarDisplayFeature feature = new SidecarDisplayFeature();
- Rect featureRect = baseFeature.getRect();
- rotateRectToDisplayRotation(displayId, featureRect);
- transformToWindowSpaceRect(activity, featureRect);
- feature.setRect(featureRect);
- feature.setType(baseFeature.getType());
- features.add(feature);
- }
+ for (CommonFoldingFeature baseFeature : mStoredFeatures) {
+ SidecarDisplayFeature feature = new SidecarDisplayFeature();
+ Rect featureRect = baseFeature.getRect();
+ rotateRectToDisplayRotation(displayId, featureRect);
+ transformToWindowSpaceRect(activity, featureRect);
+ feature.setRect(featureRect);
+ feature.setType(baseFeature.getType());
+ features.add(feature);
}
return Collections.unmodifiableList(features);
}
@@ -138,7 +135,7 @@ class SampleSidecarImpl extends StubSidecar {
@Override
protected void onListenersChanged() {
if (hasListeners()) {
- onDisplayFeaturesChanged();
+ onDisplayFeaturesChanged(mStoredFeatures);
}
}
@@ -158,7 +155,7 @@ class SampleSidecarImpl extends StubSidecar {
private void onDisplayFeaturesChangedForActivity(@NonNull Activity activity) {
IBinder token = activity.getWindow().getAttributes().token;
if (token == null || mWindowLayoutChangeListenerTokens.contains(token)) {
- onDisplayFeaturesChanged();
+ onDisplayFeaturesChanged(mStoredFeatures);
}
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java b/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java
new file mode 100644
index 000000000000..7624b693ac43
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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.util;
+
+import android.annotation.NonNull;
+
+import java.util.function.Consumer;
+
+/**
+ * A base class that works with {@link BaseDataProducer} to add/remove a consumer that should
+ * only be used once when {@link BaseDataProducer#notifyDataChanged} is called.
+ * @param <T> The type of data this producer returns through {@link DataProducer#getData}.
+ */
+public class AcceptOnceConsumer<T> implements Consumer<T> {
+ private final Consumer<T> mCallback;
+ private final DataProducer<T> mProducer;
+
+ public AcceptOnceConsumer(@NonNull DataProducer<T> producer, @NonNull Consumer<T> callback) {
+ mProducer = producer;
+ mCallback = callback;
+ }
+
+ @Override
+ public void accept(@NonNull T t) {
+ mCallback.accept(t);
+ mProducer.removeDataChangedCallback(this);
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java
index 930db3b701b7..0da44ac36a6e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java
@@ -19,38 +19,48 @@ package androidx.window.util;
import androidx.annotation.NonNull;
import java.util.LinkedHashSet;
+import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Base class that provides the implementation for the callback mechanism of the
* {@link DataProducer} API.
*
- * @param <T> The type of data this producer returns through {@link #getData()}.
+ * @param <T> The type of data this producer returns through {@link DataProducer#getData}.
*/
public abstract class BaseDataProducer<T> implements DataProducer<T> {
- private final Set<Runnable> mCallbacks = new LinkedHashSet<>();
+ private final Set<Consumer<T>> mCallbacks = new LinkedHashSet<>();
@Override
- public final void addDataChangedCallback(@NonNull Runnable callback) {
+ public final void addDataChangedCallback(@NonNull Consumer<T> callback) {
mCallbacks.add(callback);
+ Optional<T> currentData = getCurrentData();
+ currentData.ifPresent(callback);
onListenersChanged(mCallbacks);
}
@Override
- public final void removeDataChangedCallback(@NonNull Runnable callback) {
+ public final void removeDataChangedCallback(@NonNull Consumer<T> callback) {
mCallbacks.remove(callback);
onListenersChanged(mCallbacks);
}
- protected void onListenersChanged(Set<Runnable> callbacks) {}
+ protected void onListenersChanged(Set<Consumer<T>> callbacks) {}
/**
- * Called to notify all registered callbacks that the data provided by {@link #getData()} has
- * changed.
+ * @return the current data if available and {@code Optional.empty()} otherwise.
*/
- protected void notifyDataChanged() {
- for (Runnable callback : mCallbacks) {
- callback.run();
+ @NonNull
+ public abstract Optional<T> getCurrentData();
+
+ /**
+ * Called to notify all registered consumers that the data provided
+ * by {@link DataProducer#getData} has changed.
+ */
+ protected void notifyDataChanged(T value) {
+ for (Consumer<T> callback : mCallbacks) {
+ callback.accept(value);
}
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/DataProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/util/DataProducer.java
index d4d1a23b756b..ec301dc34aaa 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/DataProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/DataProducer.java
@@ -18,26 +18,27 @@ package androidx.window.util;
import android.annotation.NonNull;
-import java.util.Optional;
+import java.util.function.Consumer;
/**
- * Produces data through {@link #getData()} and provides a mechanism for receiving a callback when
- * the data managed by the produces has changed.
+ * Produces data through {@link DataProducer#getData} and provides a mechanism for receiving
+ * a callback when the data managed by the produces has changed.
*
- * @param <T> The type of data this producer returns through {@link #getData()}.
+ * @param <T> The type of data this producer returns through {@link DataProducer#getData}.
*/
public interface DataProducer<T> {
/**
- * Returns the data currently stored in the provider, or {@link Optional#empty()} if the
- * provider has no data.
+ * Emits the first available data at that point in time.
+ * @param dataConsumer a {@link Consumer} that will receive one value.
*/
- Optional<T> getData();
+ void getData(@NonNull Consumer<T> dataConsumer);
/**
- * Adds a callback to be notified when the data returned from {@link #getData()} has changed.
+ * Adds a callback to be notified when the data returned
+ * from {@link DataProducer#getData} has changed.
*/
- void addDataChangedCallback(@NonNull Runnable callback);
+ void addDataChangedCallback(@NonNull Consumer<T> callback);
- /** Removes a callback previously added with {@link #addDataChangedCallback(Runnable)}. */
- void removeDataChangedCallback(@NonNull Runnable callback);
+ /** Removes a callback previously added with {@link #addDataChangedCallback(Consumer)}. */
+ void removeDataChangedCallback(@NonNull Consumer<T> callback);
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
index b12b6f6f0ef1..c736e9ed971e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
@@ -22,6 +22,11 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
<uses-library android:name="android.test.runner" />
+
+ <activity android:name="androidx.window.extensions.embedding.MinimumDimensionActivity">
+ <layout android:minWidth="600px"
+ android:minHeight="1200px"/>
+ </activity>
</application>
<instrumentation
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
new file mode 100644
index 000000000000..835c40365cda
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 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.embedding;
+
+import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
+import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
+
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Pair;
+import android.window.TaskFragmentInfo;
+import android.window.WindowContainerToken;
+
+import java.util.Collections;
+
+public class EmbeddingTestUtils {
+ static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
+ static final int TASK_ID = 10;
+ static final float SPLIT_RATIO = 0.5f;
+ /** Default finish behavior in Jetpack. */
+ static final int DEFAULT_FINISH_PRIMARY_WITH_SECONDARY = FINISH_NEVER;
+ static final int DEFAULT_FINISH_SECONDARY_WITH_PRIMARY = FINISH_ALWAYS;
+
+ private EmbeddingTestUtils() {}
+
+ /** Gets the bounds of a TaskFragment that is in split. */
+ static Rect getSplitBounds(boolean isPrimary) {
+ final int width = (int) (TASK_BOUNDS.width() * SPLIT_RATIO);
+ return isPrimary
+ ? new Rect(TASK_BOUNDS.left, TASK_BOUNDS.top, TASK_BOUNDS.left + width,
+ TASK_BOUNDS.bottom)
+ : new Rect(
+ TASK_BOUNDS.left + width, TASK_BOUNDS.top, TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom);
+ }
+
+ /** Creates a rule to always split the given activity and the given intent. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent) {
+ final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
+ return new SplitPairRule.Builder(
+ activityPair -> false,
+ targetPair::equals,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setShouldClearTop(true)
+ .build();
+ }
+
+ /** Creates a rule to always split the given activities. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ return createSplitRule(primaryActivity, secondaryActivity,
+ DEFAULT_FINISH_PRIMARY_WITH_SECONDARY, DEFAULT_FINISH_SECONDARY_WITH_PRIMARY,
+ true /* clearTop */);
+ }
+
+ /** Creates a rule to always split the given activities with the given finish behaviors. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, int finishPrimaryWithSecondary,
+ int finishSecondaryWithPrimary, boolean clearTop) {
+ final Pair<Activity, Activity> targetPair = new Pair<>(primaryActivity, secondaryActivity);
+ return new SplitPairRule.Builder(
+ targetPair::equals,
+ activityIntentPair -> false,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setFinishPrimaryWithSecondary(finishPrimaryWithSecondary)
+ .setFinishSecondaryWithPrimary(finishSecondaryWithPrimary)
+ .setShouldClearTop(clearTop)
+ .build();
+ }
+
+ /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
+ static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
+ @NonNull Activity activity) {
+ return new TaskFragmentInfo(container.getTaskFragmentToken(),
+ mock(WindowContainerToken.class),
+ new Configuration(),
+ 1,
+ true /* isVisible */,
+ Collections.singletonList(activity.getActivityToken()),
+ new Point(),
+ false /* isTaskClearedForReuse */,
+ false /* isTaskFragmentClearedForPip */,
+ new Point());
+ }
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index a191e685f651..4d2595275f20 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -58,8 +60,6 @@ import java.util.ArrayList;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class JetpackTaskFragmentOrganizerTest {
- private static final int TASK_ID = 10;
-
@Mock
private WindowContainerTransaction mTransaction;
@Mock
@@ -131,6 +131,7 @@ public class JetpackTaskFragmentOrganizerTest {
return new TaskFragmentInfo(container.getTaskFragmentToken(),
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
false /* isVisible */, new ArrayList<>(), new Point(),
- false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */);
+ false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
+ new Point());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java
index af2ab158ab46..ffcaf3e6f546 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.wm.shell.legacysplitscreen;
+package androidx.window.extensions.embedding;
+
+import android.app.Activity;
/**
- * Class to hold state of divider that needs to persist across configuration changes.
+ * Activity that declares minWidth and minHeight in
+ * {@link android.content.pm.ActivityInfo.WindowLayout}
*/
-final class DividerState {
- public boolean animateAfterRecentsDrawn;
- public float mRatioPositionBeforeMinimized;
-}
+public class MinimumDimensionActivity extends Activity {}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 60390eb2b3d2..ef7728cec387 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -19,8 +19,13 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_RATIO;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
-import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -49,20 +54,19 @@ import android.app.Activity;
import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
import android.window.TaskFragmentInfo;
-import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -86,16 +90,9 @@ import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SplitControllerTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
- private static final float SPLIT_RATIO = 0.5f;
private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent(
new ComponentName("test", "placeholder"));
- /** Default finish behavior in Jetpack. */
- private static final int DEFAULT_FINISH_PRIMARY_WITH_SECONDARY = FINISH_NEVER;
- private static final int DEFAULT_FINISH_SECONDARY_WITH_PRIMARY = FINISH_ALWAYS;
-
private Activity mActivity;
@Mock
private Resources mActivityResources;
@@ -420,6 +417,25 @@ public class SplitControllerTest {
}
@Test
+ public void testResolveStartActivityIntent_shouldLaunchInFullscreen() {
+ final Intent intent = new Intent().setComponent(
+ new ComponentName(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class));
+ setupSplitRule(mActivity, intent);
+ final Activity primaryActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, mActivity);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, null /* launchingActivity */);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer, container));
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(null));
+ assertTrue(container.areLastRequestedBoundsEqual(null));
+ }
+
+ @Test
public void testPlaceActivityInTopContainer() {
mSplitController.placeActivityInTopContainer(mActivity);
@@ -767,6 +783,52 @@ public class SplitControllerTest {
}
@Test
+ public void testResolveActivityToContainer_primaryActivityMinDimensionsNotSatisfied() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(mActivity, activityBelow);
+
+ ActivityInfo aInfo = new ActivityInfo();
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+ primaryBounds.width() + 1, primaryBounds.height() + 1);
+ doReturn(aInfo).when(mActivity).getActivityInfo();
+
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+
+ // Allow to split as primary.
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ true /* isOnReparent */);
+
+ assertTrue(result);
+ assertSplitPair(mActivity, activityBelow, true /* matchParentBounds */);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_secondaryActivityMinDimensionsNotSatisfied() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(activityBelow, mActivity);
+
+ ActivityInfo aInfo = new ActivityInfo();
+ final Rect secondaryBounds = getSplitBounds(false /* isPrimary */);
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+ secondaryBounds.width() + 1, secondaryBounds.height() + 1);
+ doReturn(aInfo).when(mActivity).getActivityInfo();
+
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+
+ // Allow to split as primary.
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* isOnReparent */);
+
+ assertTrue(result);
+ assertSplitPair(activityBelow, mActivity, true /* matchParentBounds */);
+ }
+
+ @Test
public void testResolveActivityToContainer_inUnknownTaskFragment() {
doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
@@ -835,23 +897,10 @@ public class SplitControllerTest {
doReturn(activityToken).when(activity).getActivityToken();
doReturn(activity).when(mSplitController).getActivity(activityToken);
doReturn(TASK_ID).when(activity).getTaskId();
+ doReturn(new ActivityInfo()).when(activity).getActivityInfo();
return activity;
}
- /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
- private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
- @NonNull Activity activity) {
- return new TaskFragmentInfo(container.getTaskFragmentToken(),
- mock(WindowContainerToken.class),
- new Configuration(),
- 1,
- true /* isVisible */,
- Collections.singletonList(activity.getActivityToken()),
- new Point(),
- false /* isTaskClearedForReuse */,
- false /* isTaskFragmentClearedForPip */);
- }
-
/** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
final TaskFragmentContainer container = mSplitController.newContainer(activity, TASK_ID);
@@ -902,49 +951,10 @@ public class SplitControllerTest {
/** Setups a rule to always split the given activities. */
private void setupSplitRule(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
- final SplitRule splitRule = createSplitRule(primaryActivity, secondaryActivity,
- DEFAULT_FINISH_PRIMARY_WITH_SECONDARY, DEFAULT_FINISH_SECONDARY_WITH_PRIMARY,
- true /* clearTop */);
+ final SplitRule splitRule = createSplitRule(primaryActivity, secondaryActivity);
mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
}
- /** Creates a rule to always split the given activity and the given intent. */
- private SplitRule createSplitRule(@NonNull Activity primaryActivity,
- @NonNull Intent secondaryIntent) {
- final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
- return new SplitPairRule.Builder(
- activityPair -> false,
- targetPair::equals,
- w -> true)
- .setSplitRatio(SPLIT_RATIO)
- .setShouldClearTop(true)
- .build();
- }
-
- /** Creates a rule to always split the given activities. */
- private SplitRule createSplitRule(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity) {
- return createSplitRule(primaryActivity, secondaryActivity,
- DEFAULT_FINISH_PRIMARY_WITH_SECONDARY, DEFAULT_FINISH_SECONDARY_WITH_PRIMARY,
- true /* clearTop */);
- }
-
- /** Creates a rule to always split the given activities with the given finish behaviors. */
- private SplitRule createSplitRule(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity, int finishPrimaryWithSecondary,
- int finishSecondaryWithPrimary, boolean clearTop) {
- final Pair<Activity, Activity> targetPair = new Pair<>(primaryActivity, secondaryActivity);
- return new SplitPairRule.Builder(
- targetPair::equals,
- activityIntentPair -> false,
- w -> true)
- .setSplitRatio(SPLIT_RATIO)
- .setFinishPrimaryWithSecondary(finishPrimaryWithSecondary)
- .setFinishSecondaryWithPrimary(finishSecondaryWithPrimary)
- .setShouldClearTop(clearTop)
- .build();
- }
-
/** Adds a pair of TaskFragments as split for the given activities. */
private void addSplitTaskFragments(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
@@ -973,39 +983,42 @@ public class SplitControllerTest {
secondaryContainer.setLastRequestedBounds(getSplitBounds(false /* isPrimary */));
}
- /** Gets the bounds of a TaskFragment that is in split. */
- private Rect getSplitBounds(boolean isPrimary) {
- final int width = (int) (TASK_BOUNDS.width() * SPLIT_RATIO);
- return isPrimary
- ? new Rect(TASK_BOUNDS.left, TASK_BOUNDS.top, TASK_BOUNDS.left + width,
- TASK_BOUNDS.bottom)
- : new Rect(TASK_BOUNDS.left + width, TASK_BOUNDS.top, TASK_BOUNDS.right,
- TASK_BOUNDS.bottom);
+ /** Asserts that the two given activities are in split. */
+ private void assertSplitPair(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ assertSplitPair(primaryActivity, secondaryActivity, false /* matchParentBounds */);
}
/** Asserts that the two given activities are in split. */
private void assertSplitPair(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity) {
+ @NonNull Activity secondaryActivity, boolean matchParentBounds) {
assertSplitPair(mSplitController.getContainerWithActivity(primaryActivity),
- mSplitController.getContainerWithActivity(secondaryActivity));
+ mSplitController.getContainerWithActivity(secondaryActivity), matchParentBounds);
}
- /** Asserts that the two given TaskFragments are in split. */
private void assertSplitPair(@NonNull TaskFragmentContainer primaryContainer,
@NonNull TaskFragmentContainer secondaryContainer) {
+ assertSplitPair(primaryContainer, secondaryContainer, false /* matchParentBounds*/);
+ }
+
+ /** Asserts that the two given TaskFragments are in split. */
+ private void assertSplitPair(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer, boolean matchParentBounds) {
assertNotNull(primaryContainer);
assertNotNull(secondaryContainer);
assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer,
secondaryContainer));
if (primaryContainer.mInfo != null) {
- assertTrue(primaryContainer.areLastRequestedBoundsEqual(
- getSplitBounds(true /* isPrimary */)));
+ final Rect primaryBounds = matchParentBounds ? new Rect()
+ : getSplitBounds(true /* isPrimary */);
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(primaryBounds));
assertTrue(primaryContainer.isLastRequestedWindowingModeEqual(
WINDOWING_MODE_MULTI_WINDOW));
}
if (secondaryContainer.mInfo != null) {
- assertTrue(secondaryContainer.areLastRequestedBoundsEqual(
- getSplitBounds(false /* isPrimary */)));
+ final Rect secondaryBounds = matchParentBounds ? new Rect()
+ : getSplitBounds(false /* isPrimary */);
+ assertTrue(secondaryContainer.areLastRequestedBoundsEqual(secondaryBounds));
assertTrue(secondaryContainer.isLastRequestedWindowingModeEqual(
WINDOWING_MODE_MULTI_WINDOW));
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index 906e9904566f..acc398a27baf 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -18,25 +18,44 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_END;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_FILL;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_START;
+import static androidx.window.extensions.embedding.SplitPresenter.getBoundsForPosition;
+import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+import android.util.Size;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -56,8 +75,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SplitPresenterTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
@Mock
private Activity mActivity;
@@ -77,11 +94,7 @@ public class SplitPresenterTest {
mPresenter = mController.mPresenter;
spyOn(mController);
spyOn(mPresenter);
- final Configuration activityConfig = new Configuration();
- activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
- activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
- doReturn(mActivityResources).when(mActivity).getResources();
- doReturn(activityConfig).when(mActivityResources).getConfiguration();
+ mActivity = createMockActivity();
}
@Test
@@ -129,4 +142,67 @@ public class SplitPresenterTest {
verify(mTransaction, never()).setWindowingMode(any(), anyInt());
}
+
+ @Test
+ public void testGetMinDimensionsForIntent() {
+ final Intent intent = new Intent(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class);
+ assertEquals(new Size(600, 1200), getMinDimensions(intent));
+ }
+
+ @Test
+ public void testShouldShowSideBySide() {
+ Activity secondaryActivity = createMockActivity();
+ final SplitRule splitRule = createSplitRule(mActivity, secondaryActivity);
+
+ assertTrue(shouldShowSideBySide(TASK_BOUNDS, splitRule));
+
+ // Set minDimensions of primary container to larger than primary bounds.
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ Pair<Size, Size> minDimensionsPair = new Pair<>(
+ new Size(primaryBounds.width() + 1, primaryBounds.height() + 1), null);
+
+ assertFalse(shouldShowSideBySide(TASK_BOUNDS, splitRule, minDimensionsPair));
+ }
+
+ @Test
+ public void testGetBoundsForPosition() {
+ Activity secondaryActivity = createMockActivity();
+ final SplitRule splitRule = createSplitRule(mActivity, secondaryActivity);
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ final Rect secondaryBounds = getSplitBounds(false /* isPrimary */);
+
+ assertEquals("Primary bounds must be reported.",
+ primaryBounds,
+ getBoundsForPosition(POSITION_START, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+
+ assertEquals("Secondary bounds must be reported.",
+ secondaryBounds,
+ getBoundsForPosition(POSITION_END, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+ assertEquals("Task bounds must be reported.",
+ new Rect(),
+ getBoundsForPosition(POSITION_FILL, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+
+ Pair<Size, Size> minDimensionsPair = new Pair<>(
+ new Size(primaryBounds.width() + 1, primaryBounds.height() + 1), null);
+
+ assertEquals("Fullscreen bounds must be reported because of min dimensions.",
+ new Rect(),
+ getBoundsForPosition(POSITION_START, TASK_BOUNDS,
+ splitRule, mActivity, minDimensionsPair));
+ }
+
+ private Activity createMockActivity() {
+ final Activity activity = mock(Activity.class);
+ final Configuration activityConfig = new Configuration();
+ activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
+ activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
+ doReturn(mActivityResources).when(activity).getResources();
+ doReturn(activityConfig).when(mActivityResources).getConfiguration();
+ doReturn(new ActivityInfo()).when(activity).getActivityInfo();
+ return activity;
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index ebe202db4e54..dd67e48ef353 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -22,6 +22,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -53,9 +56,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskContainerTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
-
@Mock
private SplitController mController;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
index af3ad70c04db..d31342bfb309 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
@@ -16,6 +16,8 @@
package androidx.window.extensions.embedding;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,8 +45,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskFragmentAnimationControllerTest {
- private static final int TASK_ID = 10;
-
@Mock
private TaskFragmentOrganizer mOrganizer;
private TaskFragmentAnimationController mAnimationController;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index fcbd8a3ac020..28c2773e25cb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -16,6 +16,9 @@
package androidx.window.extensions.embedding;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
@@ -30,17 +33,13 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import android.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
-import android.content.res.Configuration;
-import android.graphics.Point;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
-import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -55,7 +54,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
@@ -68,8 +66,6 @@ import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskFragmentContainerTest {
- private static final int TASK_ID = 10;
-
@Mock
private SplitPresenter mPresenter;
@Mock
@@ -311,18 +307,4 @@ public class TaskFragmentContainerTest {
doReturn(activity).when(mController).getActivity(activityToken);
return activity;
}
-
- /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
- private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
- @NonNull Activity activity) {
- return new TaskFragmentInfo(container.getTaskFragmentToken(),
- mock(WindowContainerToken.class),
- new Configuration(),
- 1,
- true /* isVisible */,
- Collections.singletonList(activity.getActivityToken()),
- new Point(),
- false /* isTaskClearedForReuse */,
- false /* isTaskFragmentClearedForPip */);
- }
}
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
index 329e5b9b31a0..b3d260299106 100644
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -14,6 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
+ <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml
index cb516cdbe49b..df5985c605d1 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_container.xml
@@ -30,7 +30,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
- android:gravity="center"/>
+ android:gravity="center"
+ android:clipChildren="false"/>
<LinearLayout
android:id="@+id/bubble_overflow_empty_state"
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 88382d77ce35..2476f65c7e5b 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerakwessies?\nTik om aan te pas"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige programme werk beter in portret"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van hierdie opsies om jou spasie ten beste te benut"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai jou toestel om dit volskerm te maak"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik langs ’n program om dit te herposisioneer"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-af/strings_tv.xml b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
index 1bfe128b0917..6187ea46769c 100644
--- a/libs/WindowManager/Shell/res/values-af/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Beeld-in-beeld"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Titellose program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Maak PIP toe"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Maak toe"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Volskerm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Skuif PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Skuif"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Vou uit"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Vou in"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dubbeldruk "<annotation icon="home_icon">" TUIS "</annotation>" vir kontroles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Prent-in-prent-kieslys"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Skuif links"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Skuif regs"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Skuif op"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Skuif af"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klaar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 20d081f2f547..f0c391cd6b99 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"የካሜራ ችግሮች አሉ?\nዳግም ለማበጀት መታ ያድርጉ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"አንዳንድ መተግበሪያዎች በቁም ፎቶ ውስጥ በተሻለ ሁኔታ ይሰራሉ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ቦታዎን በአግባቡ ለመጠቀም ከእነዚህ አማራጮች ውስጥ አንዱን ይሞክሩ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ወደ የሙሉ ገጽ ዕይታ ለመሄድ መሣሪያዎን ያሽከርክሩት"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ቦታውን ለመቀየር ከመተግበሪያው ቀጥሎ ላይ ሁለቴ መታ ያድርጉ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index 456b4b83583a..74ce49ef078e 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ስዕል-ላይ-ስዕል"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ርዕስ የሌለው ፕሮግራም)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPን ዝጋ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ዝጋ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገጽ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ፒአይፒ ውሰድ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ውሰድ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ዘርጋ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ሰብስብ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ለመቆጣጠሪያዎች "<annotation icon="home_icon">"መነሻ"</annotation>"ን ሁለቴ ይጫኑ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"የስዕል-ላይ-ስዕል ምናሌ።"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ወደ ግራ ውሰድ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ወደ ቀኝ ውሰድ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ወደ ላይ ውሰድ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ወደ ታች ውሰድ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ተጠናቅቋል"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index b41e6421ae55..aa4b3b704110 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"هل هناك مشاكل في الكاميرا؟\nانقر لإعادة الضبط."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"تعمل بعض التطبيقات على أكمل وجه في الشاشات العمودية"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"جرِّب تنفيذ أحد هذه الخيارات للاستفادة من مساحتك إلى أقصى حد."</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"قم بتدوير الشاشة للانتقال إلى وضع ملء الشاشة."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"انقر مرتين بجانب التطبيق لتغيير موضعه."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
index 2546fe96d86a..9c195a7386a9 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"نافذة ضمن النافذة"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ليس هناك عنوان للبرنامج)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏إغلاق PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"إغلاق"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ملء الشاشة"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏نقل نافذة داخل النافذة (PIP)"</string>
+ <string name="pip_move" msgid="158770205886688553">"نقل"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"توسيع"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"تصغير"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" انقر مرتين على "<annotation icon="home_icon">" الصفحة الرئيسية "</annotation>" للوصول لعناصر التحكم."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"قائمة نافذة ضمن النافذة"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"نقل لليسار"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"نقل لليمين"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"نقل للأعلى"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"نقل للأسفل"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"تمّ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 663691fdc045..985d3b9b96fd 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"কেমেৰাৰ কোনো সমস্যা হৈছে নেকি?\nপুনৰ খাপ খোৱাবলৈ টিপক"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছুমান এপে প’ৰ্ট্ৰেইট ম’ডত বেছি ভালকৈ কাম কৰে"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপোনাৰ spaceৰ পৰা পাৰ্যমানে উপকৃত হ’বলৈ ইয়াৰে এটা বিকল্প চেষ্টা কৰি চাওক"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"পূৰ্ণ স্ক্ৰীনলৈ যাবলৈ আপোনাৰ ডিভাইচটো ঘূৰাওক"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"এপ্‌টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ কাষত দুবাৰ টিপক"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
index d17c1f3023a3..816b5b1c79dc 100644
--- a/libs/WindowManager/Shell/res/values-as/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"চিত্ৰৰ ভিতৰত চিত্ৰ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিৰোনামবিহীন কাৰ্যক্ৰম)"</string>
- <string name="pip_close" msgid="9135220303720555525">"পিপ বন্ধ কৰক"</string>
+ <string name="pip_close" msgid="2955969519031223530">"বন্ধ কৰক"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"সম্পূৰ্ণ স্ক্ৰীন"</string>
- <string name="pip_move" msgid="1544227837964635439">"পিপ স্থানান্তৰ কৰক"</string>
+ <string name="pip_move" msgid="158770205886688553">"স্থানান্তৰ কৰক"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"বিস্তাৰ কৰক"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"সংকোচন কৰক"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" নিয়ন্ত্ৰণৰ বাবে "<annotation icon="home_icon">" গৃহপৃষ্ঠা "</annotation>" বুটামত দুবাৰ হেঁচক"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"চিত্ৰৰ ভিতৰৰ চিত্ৰ মেনু।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"বাওঁফাললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"সোঁফাললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ওপৰলৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"তললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"হ’ল"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 646aba89dd64..8cd9b7a635ab 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera problemi var?\nBərpa etmək üçün toxunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bəzi tətbiqlər portret rejimində daha yaxşı işləyir"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Məkanınızdan maksimum yararlanmaq üçün bu seçimlərdən birini sınayın"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana keçmək üçün cihazınızı fırladın"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tətbiqin yerini dəyişmək üçün yanına iki dəfə toxunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings_tv.xml b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
index a5c47924e31a..ccb7a7069ad8 100644
--- a/libs/WindowManager/Shell/res/values-az/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Şəkil-içində-Şəkil"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıqsız proqram)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP bağlayın"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Bağlayın"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP tətbiq edin"</string>
+ <string name="pip_move" msgid="158770205886688553">"Köçürün"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Genişləndirin"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Yığcamlaşdırın"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nizamlayıcılar üçün "<annotation icon="home_icon">" ƏSAS SƏHİFƏ "</annotation>" süçimini iki dəfə basın"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Şəkildə şəkil menyusu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sola köçürün"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sağa köçürün"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Yuxarı köçürün"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Aşağı köçürün"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hazırdır"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 2ebdf926b357..49524c608543 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Imate problema sa kamerom?\nDodirnite da biste ponovo uklopili"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcionišu u uspravnom režimu"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste na najbolji način iskoristili prostor"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotirajte uređaj za prikaz preko celog ekrana"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste promenili njenu poziciju"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
index b4d9bd17b5fe..51a1262b1de7 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ceo ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premesti sliku u slici"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skupi"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" HOME "</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni Slika u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomerite nalevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomerite nadesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomerite nagore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomerite nadole"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 157e16895148..1767e0d66241 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Праблемы з камерай?\nНацісніце, каб пераабсталяваць"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некаторыя праграмы лепш за ўсё працуюць у кніжнай арыентацыі"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Каб эфектыўна выкарыстоўваць прастору, паспрабуйце адзін з гэтых варыянтаў"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Каб перайсці ў поўнаэкранны рэжым, павярніце прыладу"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двойчы націсніце побач з праграмай, каб перамясціць яе"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings_tv.xml b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
index 514d06b5b179..15a353c649d6 100644
--- a/libs/WindowManager/Shell/res/values-be/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Відарыс у відарысе"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Праграма без назвы)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Закрыць PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрыць"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Поўнаэкранны рэжым"</string>
- <string name="pip_move" msgid="1544227837964635439">"Перамясціць PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Перамясціць"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Разгарнуць"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Згарнуць"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Двойчы націсніце "<annotation icon="home_icon">" ГАЛОЎНЫ ЭКРАН "</annotation>" для пераходу ў налады"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню рэжыму \"Відарыс у відарысе\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Перамясціць улева"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Перамясціць управа"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Перамясціць уверх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Перамясціць уніз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Гатова"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 4ed8672db152..c22fb86a4d4d 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблеми с камерата?\nДокоснете за ремонтиране"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Някои приложения работят най-добре във вертикален режим"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Изпробвайте една от следните опции, за да се възползвате максимално от мястото на екрана"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Завъртете екрана си, за да преминете в режим на цял екран"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Докоснете два пъти дадено приложение, за да промените позицията му"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
index 19f83e71ea44..2b27a6927077 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картина в картината"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без заглавие)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затваряне на PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затваряне"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цял екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"„Картина в картина“: Преместв."</string>
+ <string name="pip_move" msgid="158770205886688553">"Преместване"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Разгъване"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Свиване"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" За достъп до контролите натиснете 2 пъти "<annotation icon="home_icon">"НАЧАЛО"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню за функцията „Картина в картината“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Преместване наляво"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Преместване надясно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Преместване нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Преместване надолу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 7579fac0ff06..c0944e0584e6 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ক্যামেরা সংক্রান্ত সমস্যা?\nরিফিট করতে ট্যাপ করুন"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছু অ্যাপ \'পোর্ট্রেট\' মোডে সবচেয়ে ভাল কাজ করে"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপনার স্পেস সবচেয়ে ভালভাবে কাজে লাগাতে এইসব বিকল্পের মধ্যে কোনও একটি ব্যবহার করে দেখুন"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"\'ফুল স্ক্রিন\' মোডে যেতে ডিভাইস ঘোরান"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"কোনও অ্যাপের পাশে ডবল ট্যাপ করে সেটির জায়গা পরিবর্তন করুন"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
index 5f90eeb35a3f..23c8ffabeede 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ছবির-মধ্যে-ছবি"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিরোনামহীন প্রোগ্রাম)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP বন্ধ করুন"</string>
+ <string name="pip_close" msgid="2955969519031223530">"বন্ধ করুন"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"পূর্ণ স্ক্রিন"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP সরান"</string>
+ <string name="pip_move" msgid="158770205886688553">"সরান"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"বড় করুন"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"আড়াল করুন"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" কন্ট্রোলের জন্য "<annotation icon="home_icon">" হোম "</annotation>" বোতামে ডবল প্রেস করুন"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ছবির-মধ্যে-ছবি মেনু।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"বাঁদিকে সরান"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ডানদিকে সরান"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"উপরে তুলুন"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"নিচে নামান"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"হয়ে গেছে"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 7b08d035c7f2..ae01c641cc43 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s kamerom?\nDodirnite da ponovo namjestite"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Određene aplikacije najbolje funkcioniraju u uspravnom načinu rada"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da maksimalno iskoristite prostor"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zarotirajte uređaj da aktivirate prikaz preko cijelog ekrana"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da promijenite njen položaj"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
index 3f2adf3600d7..443fd620fd65 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori sliku u slici"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pokreni sliku u slici"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premjesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Suzi"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" POČETNI EKRAN "</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni za način rada slika u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomjeranje ulijevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomjeranje udesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomjeranje nagore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomjeranje nadolje"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 44429cc582db..8a522b3e6397 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -27,7 +27,7 @@
<string name="pip_play" msgid="3496151081459417097">"Reprodueix"</string>
<string name="pip_pause" msgid="690688849510295232">"Posa en pausa"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
- <string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ves a l\'anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tens problemes amb la càmera?\nToca per resoldre\'ls"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunes aplicacions funcionen millor en posició vertical"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una d\'aquestes opcions per treure el màxim profit de l\'espai"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositiu per passar a pantalla completa"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Fes doble toc al costat d\'una aplicació per canviar-ne la posició"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
index db750c49884e..94ba0db7e978 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla en pantalla"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sense títol)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tanca PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tanca"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mou pantalla en pantalla"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mou"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Desplega"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Replega"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Prem dos cops "<annotation icon="home_icon">" INICI "</annotation>" per accedir als controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla en pantalla."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mou cap a l\'esquerra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mou cap a la dreta"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mou cap amunt"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mou cap avall"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fet"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index d6e7136abb07..d0cf80aef38c 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Některé aplikace fungují nejlépe na výšku"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pokud chcete maximálně využít prostor, vyzkoušejte jednu z těchto možností"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zařízení přejděte do režimu celé obrazovky"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedle aplikace změňte její umístění"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
index cef0b9951363..3ed85dce0433 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz v obraze"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Bez názvu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Ukončit obraz v obraze (PIP)"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zavřít"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
- <string name="pip_move" msgid="1544227837964635439">"Přesunout PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Přesunout"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozbalit"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sbalit"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ovládací prvky zobrazíte dvojitým stisknutím "<annotation icon="home_icon">"tlačítka plochy"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Nabídka režimu obrazu v obraze"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Přesunout doleva"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Přesunout doprava"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Přesunout nahoru"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Přesunout dolů"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index e7b8e73b7385..bb81c10c6e1b 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du problemer med dit kamera?\nTryk for at gendanne det oprindelige format"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nogle apps fungerer bedst i stående format"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv én af disse muligheder for at få mest muligt ud af dit rum"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Drej din enhed for at gå til fuld skærm"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryk to gange ud for en app for at ændre dens placering"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings_tv.xml b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
index 23305309098d..09024428a825 100644
--- a/libs/WindowManager/Shell/res/values-da/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Integreret billede"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uden titel)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Luk integreret billede"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Luk"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Fuld skærm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flyt PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flyt"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Udvid"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skjul"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tryk to gange på "<annotation icon="home_icon">" HJEM "</annotation>" for at se indstillinger"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu for integreret billede."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flyt til venstre"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flyt til højre"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flyt op"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flyt ned"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Udfør"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 57af696cacb1..c5d945a982ef 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -20,7 +20,7 @@
<string name="pip_phone_close" msgid="5783752637260411309">"Schließen"</string>
<string name="pip_phone_expand" msgid="2579292903468287504">"Maximieren"</string>
<string name="pip_phone_settings" msgid="5468987116750491918">"Einstellungen"</string>
- <string name="pip_phone_enter_split" msgid="7042877263880641911">"„Bildschirm teilen“ aktivieren"</string>
+ <string name="pip_phone_enter_split" msgid="7042877263880641911">"„Geteilter Bildschirm“ aktivieren"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
<string name="pip_notification_message" msgid="8854051911700302620">"Wenn du nicht möchtest, dass <xliff:g id="NAME">%s</xliff:g> diese Funktion verwendet, tippe, um die Einstellungen zu öffnen und die Funktion zu deaktivieren."</string>
@@ -31,7 +31,7 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"In Stash legen"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string>
- <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen bei geteiltem Bildschirmmodus nicht."</string>
+ <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen im Modus für geteilten Bildschirm nicht."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Probleme mit der Kamera?\nZum Anpassen tippen."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Einige Apps funktionieren am besten im Hochformat"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Mithilfe dieser Möglichkeiten kannst du dein Display optimal nutzen"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gerät drehen, um zum Vollbildmodus zu wechseln"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Neben einer App doppeltippen, um die Position zu ändern"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings_tv.xml b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
index 8da9110f5e03..18535c9d9338 100644
--- a/libs/WindowManager/Shell/res/values-de/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bild im Bild"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Kein Sendungsname gefunden)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP schließen"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Schließen"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Vollbild"</string>
- <string name="pip_move" msgid="1544227837964635439">"BiB verschieben"</string>
+ <string name="pip_move" msgid="158770205886688553">"Bewegen"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Maximieren"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Minimieren"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Für Steuerelemente zweimal "<annotation icon="home_icon">"STARTBILDSCHIRMTASTE"</annotation>" drücken"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menü „Bild im Bild“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Nach links bewegen"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Nach rechts bewegen"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Nach oben bewegen"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Nach unten bewegen"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fertig"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 873b3299dcf1..70f55058925c 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Προβλήματα με την κάμερα;\nΠατήστε για επιδιόρθωση."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ορισμένες εφαρμογές λειτουργούν καλύτερα σε κατακόρυφο προσανατολισμό"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Δοκιμάστε μία από αυτές τις επιλογές για να αξιοποιήσετε στο έπακρο τον χώρο σας."</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Περιστρέψτε τη συσκευή σας για μετάβαση σε πλήρη οθόνη."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Πατήστε δύο φορές δίπλα σε μια εφαρμογή για να αλλάξετε τη θέση της."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings_tv.xml b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
index df35113a8752..5f8a004b0a1f 100644
--- a/libs/WindowManager/Shell/res/values-el/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Δεν υπάρχει τίτλος προγράμματος)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Κλείσιμο PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Κλείσιμο"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Πλήρης οθόνη"</string>
- <string name="pip_move" msgid="1544227837964635439">"Μετακίνηση PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Μετακίνηση"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Ανάπτυξη"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Σύμπτυξη"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Πατήστε δύο φορές "<annotation icon="home_icon">" ΑΡΧΙΚΗ ΟΘΟΝΗ "</annotation>" για στοιχεία ελέγχου"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Μενού λειτουργίας Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Μετακίνηση αριστερά"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Μετακίνηση δεξιά"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Μετακίνηση επάνω"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Μετακίνηση κάτω"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Τέλος"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index da4933b18a8f..0b5aefa5c72e 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
index 1fb319196bef..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index da4933b18a8f..0b5aefa5c72e 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
index 1fb319196bef..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index da4933b18a8f..0b5aefa5c72e 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
index 1fb319196bef..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index da4933b18a8f..0b5aefa5c72e 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
index 1fb319196bef..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
index 3b12d90f33a2..507e066e3812 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎Picture-in-Picture‎‏‎‎‏‎"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎(No title program)‎‏‎‎‏‎"</string>
- <string name="pip_close" msgid="9135220303720555525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎Close PIP‎‏‎‎‏‎"</string>
+ <string name="pip_close" msgid="2955969519031223530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎Close‎‏‎‎‏‎"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎Full screen‎‏‎‎‏‎"</string>
- <string name="pip_move" msgid="1544227837964635439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎Move PIP‎‏‎‎‏‎"</string>
+ <string name="pip_move" msgid="158770205886688553">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎Move‎‏‎‎‏‎"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎Expand‎‏‎‎‏‎"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‎Collapse‎‏‎‎‏‎"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎ Double press ‎‏‎‎‏‏‎"<annotation icon="home_icon">"‎‏‎‎‏‏‏‎ HOME ‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎ for controls‎‏‎‎‏‎"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‎Picture-in-Picture menu.‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎Move left‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎Move right‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎Move up‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎Move down‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎Done‎‏‎‎‏‎"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 154c7abae42d..e523ae53b0cc 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Tienes problemas con la cámara?\nPresiona para reajustarla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas apps funcionan mejor en modo vertical"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba estas opciones para aprovechar al máximo tu espacio"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rota el dispositivo para ver la pantalla completa"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Presiona dos veces junto a una app para cambiar su posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
index 1beb0b5b6255..a2c27b79e04c 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla en pantalla"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sin título de programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Cerrar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expandir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Contraer"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Presiona dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla en pantalla"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover hacia la izquierda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover hacia la derecha"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover hacia arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover hacia abajo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Listo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index e2fa3a0376e0..39990dc8cb0c 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -46,10 +46,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar Modo una mano"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar modo Una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar Modo una mano"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del Modo una mano"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo Una mano"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del modo Una mano"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú adicional"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Volver a añadir a la pila"</string>
@@ -63,7 +63,7 @@
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Cerrar burbuja"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar conversación en burbuja"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatea con burbujas"</string>
- <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca una burbuja para abrirla. Arrástrala para moverla."</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamados \"burbujas\". Toca una burbuja para abrirla. Arrástrala para moverla."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla las burbujas"</string>
<string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas aplicaciones funcionan mejor en vertical"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba una de estas opciones para sacar el máximo partido al espacio de tu pantalla"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositivo para ir al modo de pantalla completa"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dos veces junto a una aplicación para cambiar su posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
index d042b43c8ce8..7993e03b2464 100644
--- a/libs/WindowManager/Shell/res/values-es/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Imagen en imagen"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sin título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Cerrar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover imagen en imagen"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Mostrar"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ocultar"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pulsa dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de imagen en imagen."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover hacia la izquierda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover hacia la derecha"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover hacia arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover hacia abajo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hecho"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index da33f4d60d2a..a5f82a6452c4 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kas teil on kaameraprobleeme?\nPuudutage ümberpaigutamiseks."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Mõni rakendus töötab kõige paremini vertikaalpaigutuses"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proovige ühte neist valikutest, et oma ruumi parimal moel kasutada"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pöörake seadet, et aktiveerida täisekraanirežiim"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Topeltpuudutage rakenduse kõrval, et selle asendit muuta"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings_tv.xml b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
index 3da16db9e196..e8fcb180c0c4 100644
--- a/libs/WindowManager/Shell/res/values-et/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pilt pildis"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programmi pealkiri puudub)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Sule PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sule"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Täisekraan"</string>
- <string name="pip_move" msgid="1544227837964635439">"Teisalda PIP-režiimi"</string>
+ <string name="pip_move" msgid="158770205886688553">"Teisalda"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Laienda"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ahenda"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nuppude nägemiseks vajutage 2 korda nuppu "<annotation icon="home_icon">"AVAKUVA"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menüü Pilt pildis."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Teisalda vasakule"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Teisalda paremale"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Teisalda üles"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Teisalda alla"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Valmis"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index e0dd3ca2c9e3..67b9a433dc03 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -23,7 +23,7 @@
<string name="pip_phone_enter_split" msgid="7042877263880641911">"Sartu pantaila zatituan"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Menua"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea nahi ez baduzu, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
<string name="pip_play" msgid="3496151081459417097">"Erreproduzitu"</string>
<string name="pip_pause" msgid="690688849510295232">"Pausatu"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Joan hurrengora"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Arazoak dauzkazu kamerarekin?\nBerriro doitzeko, sakatu hau."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Aplikazio batzuk orientazio bertikalean funtzionatzen dute hobekien"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pantailako eremuari ahalik eta etekinik handiena ateratzeko, probatu aukera hauetakoren bat"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pantaila osoko modua erabiltzeko, biratu gailua"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren ondoko edozein toki"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
index e4b57baf1e5f..07d75d2de9cd 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantaila txiki gainjarria"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa izengabea)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Itxi PIPa"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Itxi"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantaila osoa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mugitu pantaila txiki gainjarria"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mugitu"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Zabaldu"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Tolestu"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Kontrolatzeko aukerak atzitzeko, sakatu birritan "<annotation icon="home_icon">" HASIERA "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Pantaila txiki gainjarriaren menua."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Eraman ezkerrera"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Eraman eskuinera"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Eraman gora"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Eraman behera"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Eginda"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 6fcb5ee7ad6d..761fb9ddeb2f 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -48,8 +48,8 @@
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"تمام‌صفحه پایین"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"استفاده از حالت یک‌دستی"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"برای خارج شدن، از پایین صفحه‌نمایش تند به‌طرف بالا بکشید یا در هر جایی از بالای برنامه که می‌خواهید ضربه بزنید"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت تک حرکت»"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"خروج از «حالت تک حرکت»"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت یک‌دستی»"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"خروج از «حالت یک‌دستی»"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"تنظیمات برای حبابک‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"لبریزشده"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"افزودن برگشت به پشته"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"دوربین مشکل دارد؟\nبرای تنظیم مجدد اندازه ضربه بزنید"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"برخی‌از برنامه‌ها در حالت عمودی عملکرد بهتری دارند"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"با امتحان کردن یکی از این گزینه‌ها، بیشترین بهره را از فضایتان ببرید"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"برای رفتن به حالت تمام صفحه، دستگاهتان را بچرخانید"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"در کنار برنامه دوضربه بزنید تا جابه‌جا شود"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجه‌ام"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
index aaab34f807db..03f51d01a3a8 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"تصویر در تصویر"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(برنامه بدون عنوان)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏بستن PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"بستن"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"تمام صفحه"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏انتقال PIP (تصویر در تصویر)"</string>
+ <string name="pip_move" msgid="158770205886688553">"انتقال"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"گسترده کردن"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"جمع کردن"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" برای کنترل‌ها، دکمه "<annotation icon="home_icon">"صفحه اصلی"</annotation>" را دوبار فشار دهید"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"منوی تصویر در تصویر."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"انتقال به‌چپ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"انتقال به‌راست"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"انتقال به‌بالا"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"انتقال به‌پایین"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"تمام"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index fc51ad4598b7..c809b4879e71 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Onko kameran kanssa ongelmia?\nKorjaa napauttamalla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Osa sovelluksista toimii parhaiten pystytilassa"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Kokeile jotakin näistä vaihtoehdoista, jotta saat parhaan hyödyn näytön tilasta"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Käännä laitetta, niin se siirtyy koko näytön tilaan"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kaksoisnapauta sovellusta, jos haluat siirtää sitä"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
index 21c64633fac1..24ab7d99e180 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Kuva kuvassa"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nimetön)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Sulje PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sulje"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Koko näyttö"</string>
- <string name="pip_move" msgid="1544227837964635439">"Siirrä PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Siirrä"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Laajenna"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Tiivistä"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Asetukset: paina "<annotation icon="home_icon">"ALOITUSNÄYTTÖPAINIKETTA"</annotation>" kahdesti"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Kuva kuvassa ‑valikko."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Siirrä vasemmalle"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Siirrä oikealle"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Siirrä ylös"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Siirrä alas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Valmis"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 43fad3a69f4d..62b2bb65a603 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applications fonctionnent mieux en mode portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour tirer le meilleur parti de votre espace"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter votre appareil pour passer en plein écran"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
index f4baaad13999..87651ec711d9 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Incrustation d\'image"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Aucun programme de titre)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fermer mode IDI"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fermer"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Déplacer l\'image incrustée"</string>
+ <string name="pip_move" msgid="158770205886688553">"Déplacer"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Développer"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Réduire"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Appuyez deux fois sur "<annotation icon="home_icon">" ACCUEIL "</annotation>" pour les commandes"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu d\'incrustation d\'image."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Déplacer vers la gauche"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Déplacer vers la droite"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Déplacer vers le haut"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Déplacer vers le bas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 8b8cc090eee5..07475055f03e 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -63,7 +63,7 @@
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Fermer la bulle"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher la conversation dans une bulle"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatter en utilisant des bulles"</string>
- <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou de bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Contrôlez les bulles à tout moment"</string>
<string name="bubbles_user_education_manage" msgid="3460756219946517198">"Appuyez sur \"Gérer\" pour désactiver les bulles de cette application"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applis fonctionnent mieux en mode Portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour exploiter pleinement l\'espace"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter l\'appareil pour passer en plein écran"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Appuyez deux fois à côté d\'une appli pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
index 6ad8174db796..37863fb82295 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programme sans titre)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fermer mode PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fermer"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Déplacer le PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Déplacer"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Développer"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Réduire"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Menu de commandes : appuyez deux fois sur "<annotation icon="home_icon">"ACCUEIL"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu \"Picture-in-picture\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Déplacer vers la gauche"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Déplacer vers la droite"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Déplacer vers le haut"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Déplacer vers le bas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 9bc9d9338030..b8e039602243 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tes problemas coa cámara?\nToca para reaxustala"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunhas aplicacións funcionan mellor en modo vertical"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proba unha destas opcións para sacar o máximo proveito do espazo da pantalla"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xira o dispositivo para ver o contido en pantalla completa"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dúas veces a carón dunha aplicación para cambiala de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
index dcb8709d010e..5d6de76c4deb 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla superposta"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sen título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Pechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Pechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover pantalla superposta"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Despregar"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Contraer"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Preme "<annotation icon="home_icon">"INICIO"</annotation>" dúas veces para acceder aos controis"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla superposta."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover cara á esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover cara á dereita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover cara arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover cara abaixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Feito"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 032b591de660..deda2d755e20 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"કૅમેરામાં સમસ્યાઓ છે?\nફરીથી ફિટ કરવા માટે ટૅપ કરો"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"અમુક ઍપ પોર્ટ્રેટ મોડમાં શ્રેષ્ઠ રીતે કાર્ય કરે છે"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"તમારી સ્પેસનો વધુને વધુ લાભ લેવા માટે, આ વિકલ્પોમાંથી કોઈ એક અજમાવો"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"પૂર્ણ સ્ક્રીન મોડ લાગુ કરવા માટે, તમારા ડિવાઇસને ફેરવો"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બાજુમાં બે વાર ટૅપ કરો"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
index ed815caaed0f..6c1b9db73582 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ચિત્રમાં-ચિત્ર"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(કોઈ ટાઇટલ પ્રોગ્રામ નથી)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP બંધ કરો"</string>
+ <string name="pip_close" msgid="2955969519031223530">"બંધ કરો"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"પૂર્ણ સ્ક્રીન"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ખસેડો"</string>
+ <string name="pip_move" msgid="158770205886688553">"ખસેડો"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"મોટું કરો"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"નાનું કરો"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" નિયંત્રણો માટે "<annotation icon="home_icon">" હોમ "</annotation>" બટન પર બે વાર દબાવો"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ચિત્રમાં ચિત્ર મેનૂ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ડાબે ખસેડો"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"જમણે ખસેડો"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ઉપર ખસેડો"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"નીચે ખસેડો"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"થઈ ગયું"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 72fd65ce55fd..a5fcb97d1418 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -65,9 +65,9 @@
<string name="bubbles_user_education_title" msgid="2112319053732691899">"बबल्स का इस्तेमाल करके चैट करें"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"जब चाहें, बबल्स को कंट्रोल करें"</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'प्रबंधित करें\' पर टैप करें"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'मैनेज करें\' पर टैप करें"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ठीक है"</string>
- <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के कोई बबल्स नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्या कैमरे से जुड़ी कोई समस्या है?\nफिर से फ़िट करने के लिए टैप करें"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"कुछ ऐप्लिकेशन, पोर्ट्रेट मोड में सबसे अच्छी तरह काम करते हैं"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"जगह का पूरा इस्तेमाल करने के लिए, इनमें से किसी एक विकल्प को आज़माएं"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फ़ुल स्क्रीन मोड में जाने के लिए, डिवाइस को घुमाएं"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बगल में दो बार टैप करें"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
index 8bcc631b39a2..e0227253b2dc 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"पिक्चर में पिक्चर"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP बंद करें"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बंद करें"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फ़ुल स्‍क्रीन"</string>
- <string name="pip_move" msgid="1544227837964635439">"पीआईपी को दूसरी जगह लेकर जाएं"</string>
+ <string name="pip_move" msgid="158770205886688553">"ले जाएं"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"बड़ा करें"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"छोटा करें"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" कंट्रोल मेन्यू पर जाने के लिए, "<annotation icon="home_icon">" होम बटन"</annotation>" दो बार दबाएं"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"पिक्चर में पिक्चर मेन्यू."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"बाईं ओर ले जाएं"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"दाईं ओर ले जाएं"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ऊपर ले जाएं"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"नीचे ले जाएं"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"हो गया"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 5315558ea855..5ecc5585a6e9 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcioniraju u portretnom usmjerenju"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste maksimalno iskoristili prostor"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zakrenite uređaj radi prikaza na cijelom zaslonu"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste joj promijenili položaj"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
index 49b7ae0d7681..a09e6e805f63 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli zaslon"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premjesti PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premjesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sažmi"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">"POČETNI ZASLON"</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Izbornik slike u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomaknite ulijevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomaknite udesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomaknite prema gore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomaknite prema dolje"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 01671c9ba1d5..2295250e2853 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerával kapcsolatos problémába ütközött?\nKoppintson a megoldáshoz."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Egyes alkalmazások álló tájolásban működnek a leghatékonyabban"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Próbálja ki az alábbi beállítások egyikét, hogy a legjobban ki tudja használni képernyő területét"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"A teljes képernyős mód elindításához forgassa el az eszközt"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Koppintson duplán az alkalmazás mellett az áthelyezéséhez"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
index 484db0cac067..5e065c2ad4e7 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Kép a képben"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Cím nélküli program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP bezárása"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Bezárás"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Teljes képernyő"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP áthelyezése"</string>
+ <string name="pip_move" msgid="158770205886688553">"Áthelyezés"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Kibontás"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Összecsukás"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Vezérlők: "<annotation icon="home_icon">" KEZDŐKÉPERNYŐ "</annotation>" gomb kétszer megnyomva"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Kép a képben menü."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mozgatás balra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mozgatás jobbra"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mozgatás felfelé"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mozgatás lefelé"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Kész"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 459cd0a6403c..208936539094 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Տեսախցիկի հետ կապված խնդիրնե՞ր կան։\nՀպեք՝ վերակարգավորելու համար։"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Որոշ հավելվածներ լավագույնս աշխատում են դիմանկարի ռեժիմում"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Փորձեք այս տարբերակներից մեկը՝ տարածքը հնարավորինս արդյունավետ օգտագործելու համար"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Պտտեք սարքը՝ լիաէկրան ռեժիմին անցնելու համար"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
index e447ffc0d964..7963abf8972b 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Նկար նկարի մեջ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Առանց վերնագրի ծրագիր)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Փակել PIP-ն"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Փակել"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Լիէկրան"</string>
- <string name="pip_move" msgid="1544227837964635439">"Տեղափոխել PIP-ը"</string>
+ <string name="pip_move" msgid="158770205886688553">"Տեղափոխել"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Ծավալել"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ծալել"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Կարգավորումների համար կրկնակի սեղմեք "<annotation icon="home_icon">"ԳԼԽԱՎՈՐ ԷԿՐԱՆ"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"«Նկար նկարի մեջ» ռեժիմի ընտրացանկ։"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Տեղափոխել ձախ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Տեղափոխել աջ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Տեղափոխել վերև"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Տեղափոխել ներքև"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Պատրաստ է"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index e5b7421bb97a..1b46b2fe2570 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Masalah kamera?\nKetuk untuk memperbaiki"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Beberapa aplikasi berfungsi paling baik dalam mode potret"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Coba salah satu opsi berikut untuk mengoptimalkan area layar Anda"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar perangkat untuk tampilan layar penuh"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketuk dua kali di samping aplikasi untuk mengubah posisinya"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings_tv.xml b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
index b63170564734..7d37154bb86c 100644
--- a/libs/WindowManager/Shell/res/values-in/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tanpa judul)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tutup"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Layar penuh"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pindahkan PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Pindahkan"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Luaskan"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ciutkan"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" HOME "</annotation>" untuk membuka kontrol"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pindahkan ke kiri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pindahkan ke kanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pindahkan ke atas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pindahkan ke bawah"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Selesai"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 1bfec2b9840b..a201c95137f3 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sum forrit virka best í skammsniði"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prófaðu einhvern af eftirfarandi valkostum til að nýta plássið sem best"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Snúðu tækinu til að nota allan skjáinn"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ýttu tvisvar við hlið forritsins til að færa það"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings_tv.xml b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
index 119ecf088c20..1490cb98e034 100644
--- a/libs/WindowManager/Shell/res/values-is/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Mynd í mynd"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Efni án titils)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Loka mynd í mynd"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Loka"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Allur skjárinn"</string>
- <string name="pip_move" msgid="1544227837964635439">"Færa innfellda mynd"</string>
+ <string name="pip_move" msgid="158770205886688553">"Færa"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Stækka"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Minnka"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ýttu tvisvar á "<annotation icon="home_icon">" HEIM "</annotation>" til að opna stillingar"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Valmynd fyrir mynd í mynd."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Færa til vinstri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Færa til hægri"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Færa upp"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Færa niður"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Lokið"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index ebdf44b70551..7157ed088d30 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -46,10 +46,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Schermata superiore al 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Schermata superiore al 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Schermata inferiore a schermo intero"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usare la modalità one-hand"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usare la modalità a una mano"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Per uscire, scorri verso l\'alto dalla parte inferiore dello schermo oppure tocca un punto qualsiasi sopra l\'app"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Avvia la modalità one-hand"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Esci dalla modalità one-hand"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Avvia la modalità a una mano"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Esci dalla modalità a una mano"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Impostazioni per bolle <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Altre"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Aggiungi di nuovo all\'elenco"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi con la fotocamera?\nTocca per risolverli"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alcune app funzionano in modo ottimale in verticale"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una di queste opzioni per ottimizzare lo spazio a tua disposizione"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ruota il dispositivo per passare alla modalità a schermo intero"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tocca due volte accanto a un\'app per riposizionarla"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings_tv.xml b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
index 92f015c387a0..a48516f2588e 100644
--- a/libs/WindowManager/Shell/res/values-it/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture in picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma senza titolo)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Chiudi PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Chiudi"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Schermo intero"</string>
- <string name="pip_move" msgid="1544227837964635439">"Sposta PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Sposta"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Espandi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Comprimi"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Premi due volte "<annotation icon="home_icon">" HOME "</annotation>" per aprire i controlli"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Picture in picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sposta a sinistra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sposta a destra"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Sposta su"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Sposta giù"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fine"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 3a0f72b1597c..52a6b0676222 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"חלק מהאפליקציות פועלות בצורה הטובה ביותר במצב תצוגה לאורך"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"כדי להפיק את המרב משטח המסך, ניתן לנסות את אחת מהאפשרויות האלה"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"מסובבים את המכשיר כדי לעבור לתצוגה במסך מלא"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"מקישים הקשה כפולה ליד אפליקציה כדי למקם אותה מחדש"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index d09b850d01d8..2af1896d3c67 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"תמונה בתוך תמונה"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(תוכנית ללא כותרת)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏סגירת PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"סגירה"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"מסך מלא"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏העברת תמונה בתוך תמונה (PIP)"</string>
+ <string name="pip_move" msgid="158770205886688553">"העברה"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"הרחבה"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"כיווץ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" לחיצה כפולה על "<annotation icon="home_icon">" הלחצן הראשי "</annotation>" תציג את אמצעי הבקרה"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"תפריט \'תמונה בתוך תמונה\'."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"הזזה שמאלה"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"הזזה ימינה"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"הזזה למעלה"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"הזזה למטה"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"סיום"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 7b3ad248362d..5a25c24ba034 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"アプリによっては縦向きにすると正常に動作します"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"スペースを最大限に活用するには、以下の方法のいずれかをお試しください"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"全画面表示にするにはデバイスを回転させてください"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"位置を変えるにはアプリの横をダブルタップしてください"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
index d6399e537894..bc7dcb7aa029 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ピクチャー イン ピクチャー"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無題の番組)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP を閉じる"</string>
+ <string name="pip_close" msgid="2955969519031223530">"閉じる"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全画面表示"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP を移動"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"開く"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"閉じる"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" コントロールにアクセス: "<annotation icon="home_icon">" ホーム "</annotation>" を 2 回押します"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ピクチャー イン ピクチャーのメニューです。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"左に移動"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"右に移動"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"上に移動"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"下に移動"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 07ee0f9910f7..bff86fa6ffe2 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"კამერად პრობლემები აქვს?\nშეეხეთ გამოსასწორებლად"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ზოგიერთი აპი უკეთ მუშაობს პორტრეტის რეჟიმში"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"გამოცადეთ ამ ვარიანტებიდან ერთ-ერთი, რათა მაქსიმალურად ისარგებლოთ თქვენი მეხსიერებით"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"მოატრიალეთ თქვენი მოწყობილობა სრული ეკრანის გასაშლელად"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ორმაგად შეეხეთ აპის გვერდითა სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
index 8d7bee8f1398..898dac2aca88 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ეკრანი ეკრანში"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(პროგრამის სათაურის გარეშე)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP-ის დახურვა"</string>
+ <string name="pip_close" msgid="2955969519031223530">"დახურვა"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"სრულ ეკრანზე"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP გადატანა"</string>
+ <string name="pip_move" msgid="158770205886688553">"გადაადგილება"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"გაშლა"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ჩაკეცვა"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" მართვის საშუალებებზე წვდომისთვის ორმაგად დააჭირეთ "<annotation icon="home_icon">" მთავარ ღილაკს "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"მენიუ „ეკრანი ეკრანში“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"მარცხნივ გადატანა"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"მარჯვნივ გადატანა"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ზემოთ გადატანა"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ქვემოთ გადატანა"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"მზადაა"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index bdaa03eb5943..f57f3f581c85 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Кейбір қолданба портреттік режимде жақсы жұмыс істейді"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Экранды тиімді пайдалану үшін мына опциялардың бірін байқап көріңіз."</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толық экранға ауысу үшін құрылғыңызды бұрыңыз."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Қолданбаның орнын ауыстыру үшін жанынан екі рет түртіңіз."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
index 05bdcc71f293..cdf564fb4ca0 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Суреттегі сурет"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Атаусыз бағдарлама)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP жабу"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Жабу"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Толық экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP клипін жылжыту"</string>
+ <string name="pip_move" msgid="158770205886688553">"Жылжыту"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Жаю"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Жию"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Басқару элементтері: "<annotation icon="home_icon">" НЕГІЗГІ ЭКРАН "</annotation>" түймесін екі рет басыңыз."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"\"Сурет ішіндегі сурет\" мәзірі."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Солға жылжыту"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Оңға жылжыту"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Жоғары жылжыту"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Төмен жылжыту"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Дайын"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 2654765c22d9..5c04f881fe0e 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"មានបញ្ហា​ពាក់ព័ន្ធនឹង​កាមេរ៉ាឬ?\nចុចដើម្បី​ដោះស្រាយ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបាន​ដោះស្រាយ​បញ្ហានេះទេឬ?\nចុចដើម្បី​ត្រឡប់"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមាន​បញ្ហាពាក់ព័ន្ធនឹង​កាមេរ៉ាទេឬ? ចុចដើម្បី​ច្រានចោល។"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"កម្មវិធីមួយចំនួនដំណើរការបានប្រសើរបំផុតក្នុងទិសដៅបញ្ឈរ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"សាកល្បងជម្រើសមួយក្នុងចំណោមទាំងនេះ ដើម្បីទទួលបានអត្ថប្រយោជន៍ច្រើនបំផុតពីកន្លែងទំនេររបស់អ្នក"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"បង្វិលឧបករណ៍របស់អ្នក ដើម្បីចូលប្រើអេក្រង់ពេញ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ចុចពីរដងនៅជាប់កម្មវិធីណាមួយ ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings_tv.xml b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
index e8315163ad46..1a7ae813c1d3 100644
--- a/libs/WindowManager/Shell/res/values-km/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"រូបក្នុងរូប"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(កម្មវិធី​គ្មានចំណងជើង)"</string>
- <string name="pip_close" msgid="9135220303720555525">"បិទ PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"បិទ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ពេញអេក្រង់"</string>
- <string name="pip_move" msgid="1544227837964635439">"ផ្លាស់ទី PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"ផ្លាស់ទី"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ពង្រីក"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"បង្រួម"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ចុចពីរដងលើ"<annotation icon="home_icon">"ប៊ូតុងដើម"</annotation>" ដើម្បីបើកផ្ទាំងគ្រប់គ្រង"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ម៉ឺនុយ​រូប​ក្នុងរូប"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ផ្លាស់ទី​ទៅ​ឆ្វេង"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ផ្លាស់ទីទៅ​ស្តាំ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ផ្លាស់ទី​ឡើង​លើ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ផ្លាស់ទី​ចុះ​ក្រោម"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"រួចរាល់"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 6edbf13d4e2e..e91383caa009 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿವೆಯೇ?\nಮರುಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ಕೆಲವು ಆ್ಯಪ್‌ಗಳು ಪೋರ್ಟ್ರೇಟ್ ಮೋಡ್‌ನಲ್ಲಿ ಅತ್ಯುತ್ತಮವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ನಿಮ್ಮ ಸ್ಥಳಾವಕಾಶದ ಅತಿಹೆಚ್ಚು ಪ್ರಯೋಜನ ಪಡೆಯಲು ಈ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದನ್ನು ಬಳಸಿ ನೋಡಿ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ಗೆ ಹೋಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ತಿರುಗಿಸಿ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಪಕ್ಕದಲ್ಲಿ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
index 305ef668cb58..45de068c80a0 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ಮುಚ್ಚಿ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ಮುಚ್ಚಿರಿ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ಪೂರ್ಣ ಪರದೆ"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ಅನ್ನು ಸರಿಸಿ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ಸರಿಸಿ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ಕುಗ್ಗಿಸಿ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ "<annotation icon="home_icon">" ಹೋಮ್ "</annotation>" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ ಮೆನು."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ಮೇಲಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ಮುಗಿದಿದೆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 1f8d0b0b175d..104ba3f22c96 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"일부 앱은 세로 모드에서 가장 잘 작동함"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"공간을 최대한 이용할 수 있도록 이 옵션 중 하나를 시도해 보세요."</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"전체 화면 모드로 전환하려면 기기를 회전하세요."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"앱 위치를 조정하려면 앱 옆을 두 번 탭하세요."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
index 76b0adfb3d88..9e8f1f1258a5 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"PIP 모드"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(제목 없는 프로그램)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP 닫기"</string>
+ <string name="pip_close" msgid="2955969519031223530">"닫기"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"전체화면"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP 이동"</string>
+ <string name="pip_move" msgid="158770205886688553">"이동"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"펼치기"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"접기"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 제어 메뉴에 액세스하려면 "<annotation icon="home_icon">" 홈 "</annotation>"을 두 번 누르세요."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"PIP 모드 메뉴입니다."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"왼쪽으로 이동"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"오른쪽으로 이동"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"위로 이동"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"아래로 이동"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"완료"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 81eb2d70c2de..8203622a33fc 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада маселелер келип чыктыбы?\nОңдоо үчүн таптаңыз"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Айрым колдонмолорду тигинен иштетүү туура болот"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Иш чөйрөсүнүн бардык мүмкүнчүлүктөрүн пайдалануу үчүн бул параметрлердин бирин колдонуп көрүңүз"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толук экран режимине өтүү үчүн түзмөктү буруңуз"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Колдонмонун ракурсун өзгөртүү үчүн анын тушуна эки жолу басыңыз"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
index 57b955a7c5d4..19fac5876bb0 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Сүрөттөгү сүрөт"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Аталышы жок программа)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP\'ти жабуу"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Жабуу"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Толук экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP\'ти жылдыруу"</string>
+ <string name="pip_move" msgid="158770205886688553">"Жылдыруу"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Жайып көрсөтүү"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Жыйыштыруу"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Башкаруу элементтерин ачуу үчүн "<annotation icon="home_icon">" БАШКЫ БЕТ "</annotation>" баскычын эки жолу басыңыз"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Сүрөт ичиндеги сүрөт менюсу."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Солго жылдыруу"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Оңго жылдыруу"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Жогору жылдыруу"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Төмөн жылдыруу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Бүттү"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 325213020e5c..24396786f9d8 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ?\nແຕະເພື່ອປັບໃໝ່"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອ​ປິດ​ໄວ້."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ແອັບບາງຢ່າງເຮັດວຽກໄດ້ດີທີ່ສຸດໃນໂໝດລວງຕັ້ງ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ໃຫ້ລອງຕົວເລືອກໃດໜຶ່ງເຫຼົ່ານີ້ເພື່ອໃຊ້ປະໂຫຍດຈາກພື້ນທີ່ຂອງທ່ານໃຫ້ໄດ້ສູງສຸດ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ໝຸນອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ແບບເຕັມຈໍ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ແຕະສອງເທື່ອໃສ່ຖັດຈາກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
index cbea84ea7ea2..6cd0f37c516c 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ການສະແດງຜົນຊ້ອນກັນ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ໂປຣແກຣມບໍ່ມີຊື່)"</string>
- <string name="pip_close" msgid="9135220303720555525">"ປິດ PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ປິດ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ເຕັມໜ້າຈໍ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ຍ້າຍ PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"ຍ້າຍ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ຂະຫຍາຍ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ຫຍໍ້"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ກົດ "<annotation icon="home_icon">" HOME "</annotation>" ສອງເທື່ອສຳລັບການຄວບຄຸມ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ເມນູການສະແດງຜົນຊ້ອນກັນ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ຍ້າຍໄປຊ້າຍ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ຍ້າຍໄປຂວາ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ຍ້າຍຂຶ້ນ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ຍ້າຍລົງ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ແລ້ວໆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 70654c767287..e2ae643ad308 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Iškilo problemų dėl kameros?\nPalieskite, kad pritaikytumėte iš naujo"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Kai kurios programos geriausiai veikia stačiuoju režimu"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pabandykite naudoti vieną iš šių parinkčių, kad išnaudotumėte visą vietą"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pasukite įrenginį, kad įjungtumėte viso ekrano režimą"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dukart palieskite šalia programos, kad pakeistumėte jos poziciją"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
index 81716a609fc5..52017dca2b94 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Vaizdas vaizde"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa be pavadinimo)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Uždaryti PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Uždaryti"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Visas ekranas"</string>
- <string name="pip_move" msgid="1544227837964635439">"Perkelti PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Perkelti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Išskleisti"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sutraukti"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Jei reikia valdiklių, dukart paspauskite "<annotation icon="home_icon">"PAGRINDINIS"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Vaizdo vaizde meniu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Perkelti kairėn"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Perkelti dešinėn"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Perkelti aukštyn"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Perkelti žemyn"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Atlikta"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 74d1b3f6578c..a77160bc262a 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Vai ir problēmas ar kameru?\nPieskarieties, lai tās novērstu."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Dažas lietotnes vislabāk darbojas portreta režīmā"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Izmēģiniet vienu no šīm iespējām, lai efektīvi izmantotu pieejamo vietu"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pagrieziet ierīci, lai aktivizētu pilnekrāna režīmu"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Veiciet dubultskārienu blakus lietotnei, lai manītu tās pozīciju"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
index 5295cd230591..11abac6f6197 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Attēls attēlā"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma bez nosaukuma)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Aizvērt PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Aizvērt"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pilnekrāna režīms"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pārvietot attēlu attēlā"</string>
+ <string name="pip_move" msgid="158770205886688553">"Pārvietot"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Izvērst"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sakļaut"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Atvērt vadīklas: divreiz nospiediet pogu "<annotation icon="home_icon">"SĀKUMS"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Izvēlne attēlam attēlā."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pārvietot pa kreisi"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pārvietot pa labi"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pārvietot augšup"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pārvietot lejup"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gatavs"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index be6ed4d25ac1..bac0c9eee4c2 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некои апликации најдобро работат во режим на портрет"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте една од опцииве за да го извлечете максимумот од вашиот простор"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте го уредот за да отворите на цел екран"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Допрете двапати до некоја апликација за да ја преместите"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
index fa48a6cc1846..21293223b882 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Слика во слика"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без наслов)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затвори"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цел екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Премести PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Премести"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Прошири"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Собери"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Притиснете двапати на "<annotation icon="home_icon">" HOME "</annotation>" за контроли"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Мени за „Слика во слика“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Премести налево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Премести надесно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Премести нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Премести надолу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 14a341b49c0e..de0f837fcd3f 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ക്യാമറ പ്രശ്നങ്ങളുണ്ടോ?\nശരിയാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ചില ആപ്പുകൾ പോർട്രെയ്റ്റിൽ മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"നിങ്ങളുടെ ഇടം പരമാവധി പ്രയോജനപ്പെടുത്താൻ ഈ ഓപ്ഷനുകളിലൊന്ന് പരീക്ഷിക്കുക"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ഈ ഉപകരണം റൊട്ടേറ്റ് ചെയ്യുക"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ഒരു ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ, അതിന് തൊട്ടടുത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
index 533375751378..549e39b21101 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ചിത്രത്തിനുള്ളിൽ ചിത്രം"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(പേരില്ലാത്ത പ്രോഗ്രാം)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP അടയ്ക്കുക"</string>
+ <string name="pip_close" msgid="2955969519031223530">"അടയ്ക്കുക"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"പൂര്‍ണ്ണ സ്ക്രീന്‍"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP നീക്കുക"</string>
+ <string name="pip_move" msgid="158770205886688553">"നീക്കുക"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"വികസിപ്പിക്കുക"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ചുരുക്കുക"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" നിയന്ത്രണങ്ങൾക്കായി "<annotation icon="home_icon">" ഹോം "</annotation>" രണ്ട് തവണ അമർത്തുക"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ചിത്രത്തിനുള്ളിൽ ചിത്രം മെനു."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ഇടത്തേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"വലത്തേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"മുകളിലേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"താഴേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"പൂർത്തിയായി"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index b59f2825b3b5..1205306e0833 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерын асуудал гарсан уу?\nДахин тааруулахын тулд товшино уу"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Зарим апп нь босоо чиглэлд хамгийн сайн ажилладаг"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Орон зайгаа сайтар ашиглахын тулд эдгээр сонголтуудын аль нэгийг туршиж үзээрэй"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Төхөөрөмжөө бүтэн дэлгэцээр үзэхийн тулд эргүүлнэ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Аппыг дахин байрлуулахын тулд хажууд нь хоёр товшино"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
index ca1d27f29cdf..9a85d96ca602 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Дэлгэц доторх дэлгэц"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Гарчиггүй хөтөлбөр)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP-г хаах"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Хаах"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Бүтэн дэлгэц"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP-г зөөх"</string>
+ <string name="pip_move" msgid="158770205886688553">"Зөөх"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Дэлгэх"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Хураах"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Хяналтад хандах бол "<annotation icon="home_icon">" HOME "</annotation>" дээр хоёр дарна уу"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Дэлгэцэн доторх дэлгэцийн цэс."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Зүүн тийш зөөх"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Баруун тийш зөөх"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Дээш зөөх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Доош зөөх"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Болсон"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 3d2d6a36530c..c91d06fdf3d5 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"कॅमेराशी संबंधित काही समस्या आहेत का?\nपुन्हा फिट करण्यासाठी टॅप करा"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्‍यासाठी टॅप करा."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"काही ॲप्स पोर्ट्रेटमध्ये सर्वोत्तम काम करतात"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तुमच्या स्पेसचा पुरेपूर वापर करण्यासाठी, यांपैकी एक पर्याय वापरून पहा"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फुल स्क्रीन करण्यासाठी, तुमचे डिव्हाइस फिरवा"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या शेजारी दोनदा टॅप करा"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 212bd21db344..a9779b3a3e89 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"चित्रात-चित्र"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षक नसलेला कार्यक्रम)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP बंद करा"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बंद करा"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रीन"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP हलवा"</string>
+ <string name="pip_move" msgid="158770205886688553">"हलवा"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"वर हलवा"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"खाली हलवा"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"पूर्ण झाले"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 4e9a7e952a09..652a9919d163 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Isu kamera?\nKetik untuk memuatkan semula"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sesetengah apl berfungsi paling baik dalam mod potret"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Cuba salah satu daripada pilihan ini untuk memanfaatkan ruang anda sepenuhnya"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar peranti anda untuk beralih ke skrin penuh"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketik dua kali bersebelahan apl untuk menempatkan semula apl"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
index ce2912650da7..8fe992d9f3b9 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Gambar dalam Gambar"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tiada tajuk)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tutup"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Skrin penuh"</string>
- <string name="pip_move" msgid="1544227837964635439">"Alihkan PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Alih"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Kembangkan"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Kuncupkan"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" LAMAN UTAMA "</annotation>" untuk mengakses kawalan"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Gambar dalam Gambar."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Alih ke kiri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Alih ke kanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Alih ke atas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Alih ke bawah"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Selesai"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 449e50257d42..15d182c6451e 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ကင်မရာပြဿနာလား။\nပြင်ဆင်ရန် တို့ပါ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"အချို့အက်ပ်များသည် ဒေါင်လိုက်တွင် အကောင်းဆုံးလုပ်ဆောင်သည်"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"သင့်နေရာကို အကောင်းဆုံးအသုံးပြုနိုင်ရန် ဤရွေးစရာများထဲမှ တစ်ခုကို စမ်းကြည့်ပါ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ဖန်သားပြင်အပြည့်လုပ်ရန် သင့်စက်ကို လှည့်နိုင်သည်"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"အက်ပ်နေရာပြန်ချရန် ၎င်းဘေးတွင် နှစ်ချက်တို့နိုင်သည်"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ရပြီ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings_tv.xml b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
index 4847742130ba..105628d8149e 100644
--- a/libs/WindowManager/Shell/res/values-my/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"နှစ်ခုထပ်၍ကြည့်ခြင်း"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ခေါင်းစဉ်မဲ့ အစီအစဉ်)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ကိုပိတ်ပါ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ပိတ်ရန်"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"မျက်နှာပြင် အပြည့်"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ရွှေ့ရန်"</string>
+ <string name="pip_move" msgid="158770205886688553">"ရွှေ့ရန်"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ချဲ့ရန်"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"လျှော့ပြရန်"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ထိန်းချုပ်မှုအတွက် "<annotation icon="home_icon">" ပင်မခလုတ် "</annotation>" နှစ်ချက်နှိပ်ပါ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"နှစ်ခုထပ်၍ ကြည့်ခြင်းမီနူး။"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ဘယ်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ညာသို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"အပေါ်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"အောက်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ပြီးပြီ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 2172cc5d3815..2f2fea6eb833 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -63,7 +63,7 @@
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Lukk boblen"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ikke vis samtaler i bobler"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat med bobler"</string>
- <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne en boble. Dra for å flytte den."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrollér bobler når som helst"</string>
<string name="bubbles_user_education_manage" msgid="3460756219946517198">"Trykk på Administrer for å slå av bobler for denne appen"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Greit"</string>
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Noen apper fungerer best i stående format"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv et av disse alternativene for å få mest mulig ut av plassen din"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Roter enheten for å starte fullskjerm"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dobbelttrykk ved siden av en app for å flytte den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
index 7cef11c424ce..ca63518df7a5 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bilde-i-bilde"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uten tittel)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Lukk PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Lukk"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Fullskjerm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flytt BIB"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flytt"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Vis"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skjul"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dobbelttrykk på "<annotation icon="home_icon">"HJEM"</annotation>" for å åpne kontroller"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Bilde-i-bilde-meny."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flytt til venstre"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flytt til høyre"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flytt opp"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flytt ned"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Ferdig"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index ff01dcd9ff2d..8dfec88cc29d 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्यामेरासम्बन्धी समस्या देखियो?\nसमस्या हल गर्न ट्याप गर्नुहोस्"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"केही एपहरूले पोर्ट्रेटमा राम्रोसँग काम गर्छन्"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तपाईं स्क्रिनको अधिकतम ठाउँ प्रयोग गर्न चाहनुहुन्छ भने यीमध्ये कुनै विकल्प प्रयोग गरी हेर्नुहोस्"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"तपाईं फुल स्क्रिन मोड हेर्न चाहनुहुन्छ भने आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको छेउमा डबल ट्याप गर्नुहोस्"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
index 684d11490be3..7cbf9e294e7b 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षकविहीन कार्यक्रम)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP लाई बन्द गर्नुहोस्"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बन्द गर्नुहोस्"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रिन"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP सार्नुहोस्"</string>
+ <string name="pip_move" msgid="158770205886688553">"सार्नुहोस्"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"एक्स्पान्ड गर्नुहोस्"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"कोल्याप्स गर्नुहोस्"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" कन्ट्रोल मेनु खोल्न "<annotation icon="home_icon">" होम "</annotation>" बटन दुई पटक थिच्नुहोस्"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"\"picture-in-picture\" मेनु।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"बायाँतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"दायाँतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"माथितिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"तलतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"सम्पन्न भयो"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 428cb3fb65d7..8468b04c66da 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Cameraproblemen?\nTik om opnieuw passend te maken."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige apps werken het best in de staande stand"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van deze opties om optimaal gebruik te maken van je ruimte"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai je apparaat om naar volledig scherm te schakelen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
index 8562517bd58b..2deaeddc4080 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Scherm-in-scherm"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Naamloos programma)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP sluiten"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sluiten"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Volledig scherm"</string>
- <string name="pip_move" msgid="1544227837964635439">"SIS verplaatsen"</string>
+ <string name="pip_move" msgid="158770205886688553">"Verplaatsen"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Uitvouwen"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Samenvouwen"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Druk twee keer op "<annotation icon="home_icon">" HOME "</annotation>" voor bedieningselementen"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Scherm-in-scherm-menu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Naar links verplaatsen"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Naar rechts verplaatsen"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Omhoog verplaatsen"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Omlaag verplaatsen"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klaar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index f9668a1112b3..a8d8448edf99 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"କ୍ୟାମେରାରେ ସମସ୍ୟା ଅଛି?\nପୁଣି ଫିଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"କିଛି ଆପ ପୋର୍ଟ୍ରେଟରେ ସବୁଠାରୁ ଭଲ କାମ କରେ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ଆପଣଙ୍କ ସ୍ପେସରୁ ଅଧିକ ଲାଭ ପାଇବାକୁ ଏହି ବିକଳ୍ପଗୁଡ଼ିକ ମଧ୍ୟରୁ ଗୋଟିଏ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ପୂର୍ଣ୍ଣ-ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହା ପାଖରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings_tv.xml b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
index f8bc01642d88..0c1d99e4ca71 100644
--- a/libs/WindowManager/Shell/res/values-or/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ପିକଚର୍-ଇନ୍-ପିକଚର୍"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(କୌଣସି ଟାଇଟଲ୍‍ ପ୍ରୋଗ୍ରାମ୍‍ ନାହିଁ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ମୁଭ କରନ୍ତୁ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ବିସ୍ତାର କରନ୍ତୁ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପାଇଁ "<annotation icon="home_icon">" ହୋମ ବଟନ "</annotation>"କୁ ଦୁଇଥର ଦବାନ୍ତୁ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ପିକଚର-ଇନ-ପିକଚର ମେନୁ।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ଉପରକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ତଳକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ହୋଇଗଲା"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 7132597d5b11..f99176cb682d 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ?\nਮੁੜ-ਫਿੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ਕੁਝ ਐਪਾਂ ਪੋਰਟਰੇਟ ਵਿੱਚ ਬਿਹਤਰ ਕੰਮ ਕਰਦੀਆਂ ਹਨ"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ਆਪਣੀ ਜਗ੍ਹਾ ਦਾ ਵੱਧ ਤੋਂ ਵੱਧ ਲਾਹਾ ਲੈਣ ਲਈ ਇਨ੍ਹਾਂ ਵਿਕਲਪਾਂ ਵਿੱਚੋਂ ਕੋਈ ਇੱਕ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਣ ਲਈ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਘੁਮਾਓ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਅੱਗੇ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
index 1667e5fc6eac..a1edde738775 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ਸਿਰਲੇਖ-ਰਹਿਤ ਪ੍ਰੋਗਰਾਮ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ਬੰਦ ਕਰੋ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ਬੰਦ ਕਰੋ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ਨੂੰ ਲਿਜਾਓ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ਲਿਜਾਓ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ਸਮੇਟੋ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ਕੰਟਰੋਲਾਂ ਲਈ "<annotation icon="home_icon">" ਹੋਮ ਬਟਨ "</annotation>" ਨੂੰ ਦੋ ਵਾਰ ਦਬਾਓ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਮੀਨੂ।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ਉੱਪਰ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ਹੇਠਾਂ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ਹੋ ਗਿਆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index f7f97efa1a88..f2147c04d335 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemy z aparatem?\nKliknij, aby dopasować"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektóre aplikacje działają najlepiej w orientacji pionowej"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Wypróbuj jedną z tych opcji, aby jak najlepiej wykorzystać miejsce"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Obróć urządzenie, aby przejść do pełnego ekranu"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kliknij dwukrotnie obok aplikacji, aby ją przenieść"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
index 28bf66a7ee1b..2bb90addc241 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz w obrazie"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez tytułu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zamknij PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zamknij"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pełny ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Przenieś PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Przenieś"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozwiń"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Zwiń"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Naciśnij dwukrotnie "<annotation icon="home_icon">"EKRAN GŁÓWNY"</annotation>", aby wyświetlić ustawienia"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu funkcji Obraz w obrazie."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Przenieś w lewo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Przenieś w prawo"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Przenieś w górę"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Przenieś w dół"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotowe"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index a3d2ab0feffa..2efc5543dd87 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
index 27626b8ecfd6..14d1c34fd3e8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Abrir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Fechar"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu do picture-in-picture"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 86872c811857..c68a6934dead 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algumas apps funcionam melhor no modo vertical"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Experimente uma destas opções para aproveitar ao máximo o seu espaço"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rode o dispositivo para ficar em ecrã inteiro"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes junto a uma app para a reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
index a2010cee9e03..1ada4508714a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Ecrã no ecrã"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sem título do programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ecrã inteiro"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover Ecrã no ecrã"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expandir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Reduzir"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Prima duas vezes "<annotation icon="home_icon">" PÁGINA INICIAL "</annotation>" para controlos"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu de ecrã no ecrã."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index a3d2ab0feffa..2efc5543dd87 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
index 27626b8ecfd6..14d1c34fd3e8 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Abrir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Fechar"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu do picture-in-picture"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 5448e459a268..804d34f980ff 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Aveți probleme cu camera foto?\nAtingeți pentru a reîncadra"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ați remediat problema?\nAtingeți pentru a reveni"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu aveți probleme cu camera foto? Atingeți pentru a închide."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Unele aplicații funcționează cel mai bine în orientarea portret"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Încercați una dintre aceste opțiuni pentru a profita din plin de spațiu"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotiți dispozitivul pentru a trece în modul ecran complet"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Atingeți de două ori lângă o aplicație pentru a o repoziționa"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
index 18e29a60191f..56dadb2e5e65 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program fără titlu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Închideți PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Închideți"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ecran complet"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mutați fereastra PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mutați"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Extindeți"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Restrângeți"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Apăsați de două ori "<annotation icon="home_icon">"butonul ecran de pornire"</annotation>" pentru comenzi"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meniu picture-in-picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mutați spre stânga"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mutați spre dreapta"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mutați în sus"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mutați în jos"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gata"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 64e74a27d32b..95bf1cf11435 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблемы с камерой?\nНажмите, чтобы исправить."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некоторые приложения лучше работают в вертикальном режиме"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Чтобы эффективно использовать экранное пространство, выполните одно из следующих действий:"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Чтобы перейти в полноэкранный режим, поверните устройство."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Чтобы переместить приложение, нажмите на него дважды."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
index d119240adc4d..e7f55ec1bc57 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картинка в картинке"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Без названия)"</string>
- <string name="pip_close" msgid="9135220303720555525">"\"Кадр в кадре\" – выйти"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрыть"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Во весь экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Переместить PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Переместить"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Развернуть"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Свернуть"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Элементы управления: дважды нажмите "<annotation icon="home_icon">" кнопку главного экрана "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню \"Картинка в картинке\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Переместить влево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Переместить вправо"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Переместить вверх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Переместить вниз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 3cdaa72b0153..23dd65ad7b31 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"කැමරා ගැටලුද?\nයළි සවි කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්‍රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"සමහර යෙදුම් ප්‍රතිමූර්තිය තුළ හොඳින්ම ක්‍රියා කරයි"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ඔබගේ ඉඩෙන් උපරිම ප්‍රයෝජන ගැනීමට මෙම විකල්පවලින් එකක් උත්සාහ කරන්න"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"සම්පූර්ණ තිරයට යාමට ඔබගේ උපාංගය කරකවන්න"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"එය නැවත ස්ථානගත කිරීමට යෙදුමකට යාබදව දෙවරක් තට්ටු කරන්න"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings_tv.xml b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
index 86769b6ee849..5478ce5d3d40 100644
--- a/libs/WindowManager/Shell/res/values-si/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"පින්තූරය-තුළ-පින්තූරය"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(මාතෘකාවක් නැති වැඩසටහන)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP වසන්න"</string>
+ <string name="pip_close" msgid="2955969519031223530">"වසන්න"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"සම්පූර්ණ තිරය"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ගෙන යන්න"</string>
+ <string name="pip_move" msgid="158770205886688553">"ගෙන යන්න"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"දිග හරින්න"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"හකුළන්න"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" පාලන සඳහා "<annotation icon="home_icon">" මුල් පිටුව "</annotation>" දෙවරක් ඔබන්න"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"පින්තූරය තුළ පින්තූරය මෙනුව"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"වමට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"දකුණට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ඉහළට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"පහළට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"නිමයි"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index daa202175622..a231cacefb20 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s kamerou?\nKlepnutím znova upravte."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektoré aplikácie fungujú najlepšie v režime na výšku"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Vyskúšajte jednu z týchto možností a využívajte svoj priestor naplno"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zariadenia prejdete do režimu celej obrazovky"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedľa aplikácie zmeníte jej pozíciu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
index 6f6ccb703cf6..1df43afca2da 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz v obraze"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez názvu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zavrieť režim PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zavrieť"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
- <string name="pip_move" msgid="1544227837964635439">"Presunúť obraz v obraze"</string>
+ <string name="pip_move" msgid="158770205886688553">"Presunúť"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozbaliť"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Zbaliť"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ovládanie zobraz. dvoj. stlač. "<annotation icon="home_icon">" TLAČIDLA PLOCHY "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Ponuka obrazu v obraze."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Posunúť doľava"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Posunúť doprava"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Posunúť nahor"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Posunúť nadol"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index b4c7b951d14a..adeaae978eaa 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Težave s fotoaparatom?\nDotaknite se za vnovično prilagoditev"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nekatere aplikacije najbolje delujejo v navpični postavitvi"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Poskusite eno od teh možnosti za čim boljši izkoristek prostora"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Če želite preklopiti v celozaslonski način, zasukajte napravo."</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvakrat se dotaknite ob aplikaciji, če jo želite prestaviti."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
index 837794ad4be7..88fc8325aa01 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika v sliki"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program brez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zapri način PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zapri"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celozaslonsko"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premakni sliko v sliki"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premakni"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Razširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Strni"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Za kontrolnike dvakrat pritisnite gumb za "<annotation icon="home_icon">" ZAČETNI ZASLON "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni za sliko v sliki"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Premakni levo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Premakni desno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Premakni navzgor"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Premakni navzdol"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Končano"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 5051351bf340..2839b4bae7e4 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ka probleme me kamerën?\nTrokit për ta ripërshtatur"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Disa aplikacione funksionojnë më mirë në modalitetin vertikal"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Provo një nga këto opsione për ta shfrytëzuar sa më mirë hapësirën"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rrotullo ekranin për të kaluar në ekran të plotë"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Trokit dy herë pranë një aplikacioni për ta ripozicionuar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
index 107870d0489f..58687e5867fe 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Figurë brenda figurës"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program pa titull)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Mbyll PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Mbyll"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ekrani i plotë"</string>
- <string name="pip_move" msgid="1544227837964635439">"Zhvendos PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Lëviz"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Zgjero"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Palos"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Trokit dy herë "<annotation icon="home_icon">" KREU "</annotation>" për kontrollet"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menyja e \"Figurës brenda figurës\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Lëviz majtas"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Lëviz djathtas"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Lëviz lart"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Lëviz poshtë"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"U krye"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 96bb48a76368..9db6b7c63610 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблема са камером?\nДодирните да бисте поново уклопили"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Неке апликације најбоље функционишу у усправном режиму"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте једну од ових опција да бисте на најбољи начин искористили простор"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте уређај за приказ преко целог екрана"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двапут додирните поред апликације да бисте променили њену позицију"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
index ee5690ba4a9a..e850979174a3 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Слика у слици"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програм без наслова)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затвори"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цео екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Премести слику у слици"</string>
+ <string name="pip_move" msgid="158770205886688553">"Премести"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Прошири"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Скупи"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Двапут притисните "<annotation icon="home_icon">" HOME "</annotation>" за контроле"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Мени Слика у слици."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Померите налево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Померите надесно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Померите нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Померите надоле"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 9fa5c19e3dd4..f6bd55423cdc 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problem med kameran?\nTryck för att anpassa på nytt"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Vissa appar fungerar bäst i stående läge"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Testa med ett av dessa alternativ för att få ut mest möjliga av ytan"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotera skärmen för att gå över till helskärmsläge"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryck snabbt två gånger bredvid en app för att flytta den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
index 7355adf51e97..d3a9c3de66db 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bild-i-bild"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Namnlöst program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Stäng PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Stäng"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Helskärm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flytta BIB"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flytta"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Utöka"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Komprimera"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tryck snabbt två gånger på "<annotation icon="home_icon">" HEM "</annotation>" för kontroller"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Bild-i-bild-meny."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flytta åt vänster"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flytta åt höger"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flytta uppåt"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flytta nedåt"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 8c026f96392d..f6e558527ee5 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Je, kuna hitilafu za kamera?\nGusa ili urekebishe"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Baadhi ya programu hufanya kazi vizuri zaidi zikiwa wima"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Jaribu moja kati ya chaguo hizi ili utumie nafasi ya skrini yako kwa ufanisi"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungusha kifaa chako ili uende kwenye hali ya skrini nzima"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Gusa mara mbili karibu na programu ili uihamishe"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
index 0ee28416137a..7b9a310ff0b6 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pachika Picha Ndani ya Picha Nyingine"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programu isiyo na jina)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Funga PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Funga"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Skrini nzima"</string>
- <string name="pip_move" msgid="1544227837964635439">"Kuhamisha PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Hamisha"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Panua"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Kunja"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Bonyeza mara mbili kitufe cha "<annotation icon="home_icon">" UKURASA WA KWANZA "</annotation>" kupata vidhibiti"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menyu ya kipengele cha kupachika picha ndani ya picha nyingine."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sogeza kushoto"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sogeza kulia"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Sogeza juu"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Sogeza chini"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Imemaliza"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index cb3d138035b2..d8334adfe5ef 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"சில ஆப்ஸ் \'போர்ட்ரெய்ட்டில்\' சிறப்பாகச் செயல்படும்"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ஸ்பேஸ்களிலிருந்து அதிகப் பலன்களைப் பெற இந்த விருப்பங்களில் ஒன்றைப் பயன்படுத்துங்கள்"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"முழுத்திரைக்குச் செல்ல உங்கள் சாதனத்தைச் சுழற்றவும்"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ஆப்ஸை இடம் மாற்ற, ஆப்ஸுக்கு அடுத்து இருமுறை தட்டவும்"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
index 8bcc43bea59a..e201401e2e35 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"பிக்ச்சர்-இன்-பிக்ச்சர்"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(தலைப்பு இல்லை)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPஐ மூடு"</string>
+ <string name="pip_close" msgid="2955969519031223530">"மூடுக"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"முழுத்திரை"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPபை நகர்த்து"</string>
+ <string name="pip_move" msgid="158770205886688553">"நகர்த்து"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"விரி"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"சுருக்கு"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" கட்டுப்பாடுகள்: "<annotation icon="home_icon">" முகப்பு "</annotation>" பட்டனை இருமுறை அழுத்துக"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"பிக்ச்சர்-இன்-பிக்ச்சர் மெனு."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"இடப்புறம் நகர்த்து"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"வலப்புறம் நகர்த்து"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"மேலே நகர்த்து"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"கீழே நகர்த்து"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"முடிந்தது"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 7589e70cc681..733075550007 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"కెమెరా సమస్యలు ఉన్నాయా?\nరీఫిట్ చేయడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"కొన్ని యాప్‌లు పోర్ట్రెయిట్‌లో ఉత్తమంగా పని చేస్తాయి"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"మీ ప్రదేశాన్ని ఎక్కువగా ఉపయోగించుకోవడానికి ఈ ఆప్షన్‌లలో ఒకదాన్ని ట్రై చేయండి"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ఫుల్ స్క్రీన్‌కు వెళ్లడానికి మీ పరికరాన్ని తిప్పండి"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"యాప్ స్థానాన్ని మార్చడానికి దాని పక్కన డబుల్-ట్యాప్ చేయండి"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings_tv.xml b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
index 6e80bd7b3a0c..6284d90cb11f 100644
--- a/libs/WindowManager/Shell/res/values-te/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"పిక్చర్-ఇన్-పిక్చర్"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(శీర్షిక లేని ప్రోగ్రామ్)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPని మూసివేయి"</string>
+ <string name="pip_close" msgid="2955969519031223530">"మూసివేయండి"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ఫుల్-స్క్రీన్‌"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPను తరలించండి"</string>
+ <string name="pip_move" msgid="158770205886688553">"తరలించండి"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"విస్తరించండి"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"కుదించండి"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" కంట్రోల్స్ కోసం "<annotation icon="home_icon">" HOME "</annotation>" బటన్ రెండుసార్లు నొక్కండి"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"పిక్చర్-ఇన్-పిక్చర్ మెనూ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ఎడమ వైపుగా జరపండి"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"కుడి వైపుగా జరపండి"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"పైకి జరపండి"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"కిందికి జరపండి"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"పూర్తయింది"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index d8a33ff4c8e5..cfee8ea3242e 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"หากพบปัญหากับกล้อง\nแตะเพื่อแก้ไข"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"บางแอปทำงานได้ดีที่สุดในแนวตั้ง"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ลองใช้หนึ่งในตัวเลือกเหล่านี้เพื่อให้ได้ประโยชน์สูงสุดจากพื้นที่ว่าง"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"หมุนอุปกรณ์ให้แสดงเต็มหน้าจอ"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"แตะสองครั้งข้างแอปเพื่อเปลี่ยนตำแหน่ง"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings_tv.xml b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
index b6f63699cc00..27cf56c6e154 100644
--- a/libs/WindowManager/Shell/res/values-th/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"การแสดงภาพซ้อนภาพ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ไม่มีชื่อรายการ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"ปิด PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ปิด"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"เต็มหน้าจอ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ย้าย PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"ย้าย"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ขยาย"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ยุบ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" กดปุ่ม "<annotation icon="home_icon">" หน้าแรก "</annotation>" สองครั้งเพื่อเปิดการควบคุม"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"เมนูการแสดงภาพซ้อนภาพ"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ย้ายไปทางซ้าย"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ย้ายไปทางขวา"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ย้ายขึ้น"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ย้ายลง"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"เสร็จ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 35a58b33931d..eed624dd5069 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"May mga isyu sa camera?\nI-tap para i-refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"May ilang app na pinakamainam gamitin nang naka-portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Subukan ang isa sa mga opsyong ito para masulit ang iyong space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"I-rotate ang iyong device para mag-full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Mag-double tap sa tabi ng isang app para iposisyon ito ulit"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
index 71ca2306ea03..4cc050bebe5b 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Walang pamagat na programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Isara ang PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Isara"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Ilipat ang PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Ilipat"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"I-expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"I-collapse"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" I-double press ang "<annotation icon="home_icon">" HOME "</annotation>" para sa mga kontrol"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu ng Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Ilipat pakaliwa"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Ilipat pakanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Itaas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Ibaba"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Tapos na"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 8a9fb7546a20..2b4a2d0550f0 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kameranızda sorun mu var?\nDüzeltmek için dokunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bazı uygulamalar dikey modda en iyi performansı gösterir"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Alanınızı en verimli şekilde kullanmak için bu seçeneklerden birini deneyin"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana geçmek için cihazınızı döndürün"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Yeniden konumlandırmak için uygulamanın yanına iki kez dokunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
index e6ae7f167758..69bb608061e4 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pencere İçinde Pencere"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıksız program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP\'yi kapat"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Kapat"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP\'yi taşı"</string>
+ <string name="pip_move" msgid="158770205886688553">"Taşı"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Genişlet"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Daralt"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Kontroller için "<annotation icon="home_icon">" ANA SAYFA "</annotation>" düğmesine iki kez basın"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Pencere içinde pencere menüsü."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sola taşı"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sağa taşı"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Yukarı taşı"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Aşağı taşı"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Bitti"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index aac9031a7ca7..c3411a837c78 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми з камерою?\nНатисніть, щоб пристосувати"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Деякі додатки найкраще працюють у вертикальній орієнтації"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Щоб максимально ефективно використовувати місце на екрані, спробуйте виконати одну з наведених нижче дій"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Щоб перейти в повноекранний режим, поверніть пристрій"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Щоб перемістити додаток, двічі торкніться області поруч із ним"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
index 97e1f09844fa..81a8285c58cf 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картинка в картинці"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без назви)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Закрити PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрити"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"На весь екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Перемістити картинку в картинці"</string>
+ <string name="pip_move" msgid="158770205886688553">"Перемістити"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Розгорнути"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Згорнути"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Відкрити елементи керування: двічі натисніть "<annotation icon="home_icon">"HOME"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню \"картинка в картинці\""</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Перемістити ліворуч"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Перемістити праворуч"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Перемістити вгору"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Перемістити вниз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index e3bab32f309d..a31c2be25643 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"کیمرے کے مسائل؟\nدوبارہ فٹ کرنے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"کچھ ایپس پورٹریٹ میں بہترین کام کرتی ہیں"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"اپنی اسپیس کا زیادہ سے زیادہ فائدہ اٹھانے کے لیے ان اختیارات میں سے ایک کو آزمائیں"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"پوری اسکرین پر جانے کیلئے اپنا آلہ گھمائیں"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس کے آگے دو بار تھپتھپائیں"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
index 1418570f2538..e83885772f2d 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"تصویر میں تصویر"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(بلا عنوان پروگرام)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏PIP بند کریں"</string>
+ <string name="pip_close" msgid="2955969519031223530">"بند کریں"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"فُل اسکرین"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏PIP کو منتقل کریں"</string>
+ <string name="pip_move" msgid="158770205886688553">"منتقل کریں"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"پھیلائیں"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"سکیڑیں"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" کنٹرولز کے لیے "<annotation icon="home_icon">"ہوم "</annotation>" بٹن کو دو بار دبائیں"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"تصویر میں تصویر کا مینو۔"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"دائیں منتقل کریں"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"بائیں منتقل کریں"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"اوپر منتقل کریں"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"نیچے منتقل کریں"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ہو گیا"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 54ec89ae6b30..2e3222560dde 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera nosozmi?\nQayta moslash uchun bosing"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ayrim ilovalar tik holatda ishlashga eng mos"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Muhitdan yanada samarali foydalanish uchun quyidagilardan birini sinang"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Butun ekranda ochish uchun qurilmani buring"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Qayta joylash uchun keyingi ilova ustiga ikki marta bosing"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
index 31c762ef5f64..da953356628c 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Tasvir ustida tasvir"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nomsiz)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Kadr ichida kadr – chiqish"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Yopish"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Butun ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPni siljitish"</string>
+ <string name="pip_move" msgid="158770205886688553">"Boshqa joyga olish"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Yoyish"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Yopish"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Boshqaruv uchun "<annotation icon="home_icon">"ASOSIY"</annotation>" tugmani ikki marta bosing"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Tasvir ustida tasvir menyusi."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Chapga olish"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Oʻngga olish"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Tepaga olish"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pastga olish"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Tayyor"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index b6837023ccb8..8f3cffecc952 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Một số ứng dụng hoạt động tốt nhất ở chế độ dọc"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Hãy thử một trong các tuỳ chọn sau để tận dụng không gian"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xoay thiết bị để chuyển sang chế độ toàn màn hình"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Nhấn đúp vào bên cạnh ứng dụng để đặt lại vị trí"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
index b46cd49c1901..1f9260fdcff0 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Hình trong hình"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Không có chương trình tiêu đề)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Đóng PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Đóng"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Toàn màn hình"</string>
- <string name="pip_move" msgid="1544227837964635439">"Di chuyển PIP (Ảnh trong ảnh)"</string>
+ <string name="pip_move" msgid="158770205886688553">"Di chuyển"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Mở rộng"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Thu gọn"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nhấn đúp vào nút "<annotation icon="home_icon">" MÀN HÌNH CHÍNH "</annotation>" để mở trình đơn điều khiển"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Trình đơn hình trong hình."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Di chuyển sang trái"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Di chuyển sang phải"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Di chuyển lên"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Di chuyển xuống"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Xong"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 811d8602a499..19a9d371e435 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相机有问题?\n点按即可整修"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些应用在纵向模式下才能发挥最佳效果"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"这些选项都有助于您最大限度地利用屏幕空间,不妨从中择一试试"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋转设备即可进入全屏模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在某个应用旁边连续点按两次,即可调整它的位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
index b6fec635a470..399d639fe70f 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"画中画"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(节目没有标题)"</string>
- <string name="pip_close" msgid="9135220303720555525">"关闭画中画"</string>
+ <string name="pip_close" msgid="2955969519031223530">"关闭"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全屏"</string>
- <string name="pip_move" msgid="1544227837964635439">"移动画中画窗口"</string>
+ <string name="pip_move" msgid="158770205886688553">"移动"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展开"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收起"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按两次"<annotation icon="home_icon">"主屏幕"</annotation>"按钮可查看相关控件"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"画中画菜单。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"左移"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"右移"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"上移"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"下移"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 2a017148f7c4..0c40e963f2e4 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題?\n輕按即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"部分應用程式需要使用直向模式才能發揮最佳效果"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請嘗試以下選項,充分運用螢幕的畫面空間"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕按兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
index b5d54cb04354..acbc26d033cd 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"畫中畫"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(沒有標題的節目)"</string>
- <string name="pip_close" msgid="9135220303720555525">"關閉 PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"關閉"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
- <string name="pip_move" msgid="1544227837964635439">"移動畫中畫"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展開"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收合"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">" 主畫面按鈕"</annotation>"即可顯示控制項"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"畫中畫選單。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"向左移"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"向右移"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"向上移"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"向下移"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 292a43912668..8691352cf94a 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題嗎?\n輕觸即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些應用程式在直向模式下才能發揮最佳效果"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請試試這裡的任一方式,以充分運用螢幕畫面的空間"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕觸兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
index 57db7a839ea2..f8c683ec3a60 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"子母畫面"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無標題的節目)"</string>
- <string name="pip_close" msgid="9135220303720555525">"關閉子母畫面"</string>
+ <string name="pip_close" msgid="2955969519031223530">"關閉"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
- <string name="pip_move" msgid="1544227837964635439">"移動子母畫面"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展開"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收合"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">"主畫面按鈕"</annotation>"即可顯示控制選項"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"子母畫面選單。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"向左移動"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"向右移動"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"向上移動"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"向下移動"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 389eb08bf154..44ffbc6afa45 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -76,13 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Izinkinga zekhamera?\nThepha ukuze uyilinganise kabusha"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
- <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
- <skip />
- <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
- <skip />
- <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
- <skip />
- <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
- <skip />
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Amanye ama-app asebenza ngcono uma eme ngobude"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Zama enye yalezi zinketho ukuze usebenzise isikhala sakho ngokugcwele"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungezisa idivayisi yakho ukuze uye esikrinini esigcwele"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Thepha kabili eduze kwe-app ukuze uyimise kabusha"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
index 646a488e4c35..20243a9dfc9c 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
@@ -19,7 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Isithombe-esithombeni"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Alukho uhlelo lwesihloko)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Vala i-PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Vala"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Iskrini esigcwele"</string>
- <string name="pip_move" msgid="1544227837964635439">"Hambisa i-PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Hambisa"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Nweba"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Goqa"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Chofoza kabili "<annotation icon="home_icon">" IKHAYA"</annotation>" mayelana nezilawuli"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Imenyu yesithombe-esithombeni"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Yisa kwesokunxele"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Yisa kwesokudla"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Khuphula"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Yehlisa"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Kwenziwe"</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 06f4367752fb..c5f7c19518a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -18,11 +18,9 @@ package com.android.wm.shell;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasksController;
@@ -39,12 +37,10 @@ import java.util.Optional;
public final class ShellCommandHandlerImpl {
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
- private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHandedController> mOneHandedOptional;
private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
- private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<RecentTasksController> mRecentTasks;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
@@ -54,23 +50,19 @@ public final class ShellCommandHandlerImpl {
public ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
KidsModeTaskOrganizer kidsModeTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
- Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasks,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mRecentTasks = recentTasks;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mPipOptional = pipOptional;
mOneHandedOptional = oneHandedOptional;
mHideDisplayCutout = hideDisplayCutout;
- mAppPairsOptional = appPairsOptional;
mMainExecutor = mainExecutor;
}
@@ -84,14 +76,10 @@ public final class ShellCommandHandlerImpl {
pw.println();
pw.println();
mPipOptional.ifPresent(pip -> pip.dump(pw));
- mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
pw.println();
pw.println();
- mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
- pw.println();
- pw.println();
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
pw.println();
pw.println();
@@ -109,10 +97,6 @@ public final class ShellCommandHandlerImpl {
return false;
}
switch (args[1]) {
- case "pair":
- return runPair(args, pw);
- case "unpair":
- return runUnpair(args, pw);
case "moveToSideStage":
return runMoveToSideStage(args, pw);
case "removeFromSideStage":
@@ -126,29 +110,6 @@ public final class ShellCommandHandlerImpl {
}
}
- private boolean runPair(String[] args, PrintWriter pw) {
- if (args.length < 4) {
- // First two arguments are "WMShell" and command name.
- pw.println("Error: two task ids should be provided as arguments");
- return false;
- }
- final int taskId1 = new Integer(args[2]);
- final int taskId2 = new Integer(args[3]);
- mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
- return true;
- }
-
- private boolean runUnpair(String[] args, PrintWriter pw) {
- if (args.length < 3) {
- // First two arguments are "WMShell" and command name.
- pw.println("Error: task id should be provided as an argument");
- return false;
- }
- final int taskId = new Integer(args[2]);
- mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
- return true;
- }
-
private boolean runMoveToSideStage(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First arguments are "WMShell" and command name.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 62fb840d29d1..f6a3e7fb54d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -18,7 +18,6 @@ package com.android.wm.shell;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -34,6 +33,7 @@ import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.UnfoldTransitionHandler;
@@ -53,7 +53,6 @@ public class ShellInitImpl {
private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final Optional<BubbleController> mBubblesOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
- private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
@@ -75,7 +74,6 @@ public class ShellInitImpl {
KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
- Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
@@ -93,7 +91,6 @@ public class ShellInitImpl {
mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mBubblesOptional = bubblesOptional;
mSplitScreenOptional = splitScreenOptional;
- mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mPipTouchHandlerOptional = pipTouchHandlerOptional;
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
@@ -121,7 +118,6 @@ public class ShellInitImpl {
mShellTaskOrganizer.initStartingWindow(mStartingWindow);
mShellTaskOrganizer.registerOrganizer();
- mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);
mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
mBubblesOptional.ifPresent(BubbleController::initialize);
@@ -131,6 +127,13 @@ public class ShellInitImpl {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.register(mShellTaskOrganizer);
mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init);
+ if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
+ final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
+ mPipTouchHandlerOptional.get().getTransitionHandler(),
+ mSplitScreenOptional.get().getTransitionHandler());
+ // Added at end so that it has highest priority.
+ mTransitions.addHandler(mixedHandler);
+ }
}
// TODO(b/181599115): This should really be the pip controller, but until we can provide the
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 31f0ef0192ae..b20caf4b46bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -439,6 +439,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
notifyLocusVisibilityIfNeeded(info.getTaskInfo());
notifyCompatUI(info.getTaskInfo(), listener);
+ mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 2aead9392e59..a0dde6ad168d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -53,6 +53,19 @@ public class Interpolators {
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
/**
+ * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+ * is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 0.8f, 0.15f);
+
+ /**
+ * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+ * is appearing e.g. when coming from off screen
+ */
+ public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+ 0.05f, 0.7f, 0.1f, 1f);
+ /**
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
*/
public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
deleted file mode 100644
index 3f0b01bef0ce..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ /dev/null
@@ -1,357 +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.apppairs;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.SurfaceUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.split.SplitLayout;
-import com.android.wm.shell.common.split.SplitWindowManager;
-
-import java.io.PrintWriter;
-
-/**
- * An app-pairs consisting of {@link #mRootTaskInfo} that acts as the hierarchy parent of
- * {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
- * Also includes all UI for managing the pair like the divider.
- */
-class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayoutHandler {
- private static final String TAG = AppPair.class.getSimpleName();
-
- private ActivityManager.RunningTaskInfo mRootTaskInfo;
- private SurfaceControl mRootTaskLeash;
- private ActivityManager.RunningTaskInfo mTaskInfo1;
- private SurfaceControl mTaskLeash1;
- private ActivityManager.RunningTaskInfo mTaskInfo2;
- private SurfaceControl mTaskLeash2;
- private SurfaceControl mDimLayer1;
- private SurfaceControl mDimLayer2;
- private final SurfaceSession mSurfaceSession = new SurfaceSession();
-
- private final AppPairsController mController;
- private final SyncTransactionQueue mSyncQueue;
- private final DisplayController mDisplayController;
- private final DisplayImeController mDisplayImeController;
- private final DisplayInsetsController mDisplayInsetsController;
- private SplitLayout mSplitLayout;
-
- private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
- new SplitWindowManager.ParentContainerCallbacks() {
- @Override
- public void attachToParentSurface(SurfaceControl.Builder b) {
- b.setParent(mRootTaskLeash);
- }
-
- @Override
- public void onLeashReady(SurfaceControl leash) {
- mSyncQueue.runInSync(t -> t
- .show(leash)
- .setLayer(leash, Integer.MAX_VALUE)
- .setPosition(leash,
- mSplitLayout.getDividerBounds().left,
- mSplitLayout.getDividerBounds().top));
- }
- };
-
- AppPair(AppPairsController controller) {
- mController = controller;
- mSyncQueue = controller.getSyncTransactionQueue();
- mDisplayController = controller.getDisplayController();
- mDisplayImeController = controller.getDisplayImeController();
- mDisplayInsetsController = controller.getDisplayInsetsController();
- }
-
- int getRootTaskId() {
- return mRootTaskInfo != null ? mRootTaskInfo.taskId : INVALID_TASK_ID;
- }
-
- private int getTaskId1() {
- return mTaskInfo1 != null ? mTaskInfo1.taskId : INVALID_TASK_ID;
- }
-
- private int getTaskId2() {
- return mTaskInfo2 != null ? mTaskInfo2.taskId : INVALID_TASK_ID;
- }
-
- boolean contains(int taskId) {
- return taskId == getRootTaskId() || taskId == getTaskId1() || taskId == getTaskId2();
- }
-
- boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
- ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s",
- task1.taskId, task2.taskId, this);
-
- if (!task1.supportsMultiWindow || !task2.supportsMultiWindow) {
- ProtoLog.e(WM_SHELL_TASK_ORG,
- "Can't pair tasks that doesn't support multi window, "
- + "task1.supportsMultiWindow=%b, task2.supportsMultiWindow=%b",
- task1.supportsMultiWindow, task2.supportsMultiWindow);
- return false;
- }
-
- mTaskInfo1 = task1;
- mTaskInfo2 = task2;
- mSplitLayout = new SplitLayout(TAG + "SplitDivider",
- mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
- mRootTaskInfo.configuration, this /* layoutChangeListener */,
- mParentContainerCallbacks, mDisplayImeController, mController.getTaskOrganizer(),
- SplitLayout.PARALLAX_DISMISSING);
- mDisplayInsetsController.addInsetsChangedListener(mRootTaskInfo.displayId, mSplitLayout);
-
- final WindowContainerToken token1 = task1.token;
- final WindowContainerToken token2 = task2.token;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- wct.setHidden(mRootTaskInfo.token, false)
- .reparent(token1, mRootTaskInfo.token, true /* onTop */)
- .reparent(token2, mRootTaskInfo.token, true /* onTop */)
- .setWindowingMode(token1, WINDOWING_MODE_MULTI_WINDOW)
- .setWindowingMode(token2, WINDOWING_MODE_MULTI_WINDOW)
- .setBounds(token1, mSplitLayout.getBounds1())
- .setBounds(token2, mSplitLayout.getBounds2())
- // Moving the root task to top after the child tasks were repareted , or the root
- // task cannot be visible and focused.
- .reorder(mRootTaskInfo.token, true);
- mController.getTaskOrganizer().applyTransaction(wct);
- return true;
- }
-
- void unpair() {
- unpair(null /* toTopToken */);
- }
-
- private void unpair(@Nullable WindowContainerToken toTopToken) {
- final WindowContainerToken token1 = mTaskInfo1.token;
- final WindowContainerToken token2 = mTaskInfo2.token;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- // Reparent out of this container and reset windowing mode.
- wct.setHidden(mRootTaskInfo.token, true)
- .reorder(mRootTaskInfo.token, false)
- .reparent(token1, null, token1 == toTopToken /* onTop */)
- .reparent(token2, null, token2 == toTopToken /* onTop */)
- .setWindowingMode(token1, WINDOWING_MODE_UNDEFINED)
- .setWindowingMode(token2, WINDOWING_MODE_UNDEFINED);
- mController.getTaskOrganizer().applyTransaction(wct);
-
- mTaskInfo1 = null;
- mTaskInfo2 = null;
- mSplitLayout.release();
- mSplitLayout = null;
- }
-
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) {
- mRootTaskInfo = taskInfo;
- mRootTaskLeash = leash;
- } else if (taskInfo.taskId == getTaskId1()) {
- mTaskInfo1 = taskInfo;
- mTaskLeash1 = leash;
- mSyncQueue.runInSync(t -> mDimLayer1 =
- SurfaceUtils.makeDimLayer(t, mTaskLeash1, "Dim layer", mSurfaceSession));
- } else if (taskInfo.taskId == getTaskId2()) {
- mTaskInfo2 = taskInfo;
- mTaskLeash2 = leash;
- mSyncQueue.runInSync(t -> mDimLayer2 =
- SurfaceUtils.makeDimLayer(t, mTaskLeash2, "Dim layer", mSurfaceSession));
- } else {
- throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
- }
-
- if (mTaskLeash1 == null || mTaskLeash2 == null) return;
-
- mSplitLayout.init();
-
- mSyncQueue.runInSync(t -> t
- .show(mRootTaskLeash)
- .show(mTaskLeash1)
- .show(mTaskLeash2)
- .setPosition(mTaskLeash1,
- mTaskInfo1.positionInParent.x,
- mTaskInfo1.positionInParent.y)
- .setPosition(mTaskLeash2,
- mTaskInfo2.positionInParent.x,
- mTaskInfo2.positionInParent.y));
- }
-
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (!taskInfo.supportsMultiWindow) {
- // Dismiss AppPair if the task no longer supports multi window.
- mController.unpair(mRootTaskInfo.taskId);
- return;
- }
- if (taskInfo.taskId == getRootTaskId()) {
- if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
- mSyncQueue.runInSync(t -> {
- if (taskInfo.isVisible) {
- t.show(mRootTaskLeash);
- } else {
- t.hide(mRootTaskLeash);
- }
- });
- }
- mRootTaskInfo = taskInfo;
-
- if (mSplitLayout != null
- && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- onLayoutSizeChanged(mSplitLayout);
- }
- } else if (taskInfo.taskId == getTaskId1()) {
- mTaskInfo1 = taskInfo;
- } else if (taskInfo.taskId == getTaskId2()) {
- mTaskInfo2 = taskInfo;
- } else {
- throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
- }
- }
-
- @Override
- public int getSplitItemPosition(WindowContainerToken token) {
- if (token == null) {
- return SPLIT_POSITION_UNDEFINED;
- }
-
- if (token.equals(mTaskInfo1.getToken())) {
- return SPLIT_POSITION_TOP_OR_LEFT;
- } else if (token.equals(mTaskInfo2.getToken())) {
- return SPLIT_POSITION_BOTTOM_OR_RIGHT;
- }
-
- return SPLIT_POSITION_UNDEFINED;
- }
-
- @Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- if (taskInfo.taskId == getRootTaskId()) {
- // We don't want to release this object back to the pool since the root task went away.
- mController.unpair(mRootTaskInfo.taskId, false /* releaseToPool */);
- } else if (taskInfo.taskId == getTaskId1()) {
- mController.unpair(mRootTaskInfo.taskId);
- mSyncQueue.runInSync(t -> t.remove(mDimLayer1));
- } else if (taskInfo.taskId == getTaskId2()) {
- mController.unpair(mRootTaskInfo.taskId);
- mSyncQueue.runInSync(t -> t.remove(mDimLayer2));
- }
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- b.setParent(findTaskSurface(taskId));
- }
-
- @Override
- public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
- SurfaceControl.Transaction t) {
- t.reparent(sc, findTaskSurface(taskId));
- }
-
- private SurfaceControl findTaskSurface(int taskId) {
- if (getRootTaskId() == taskId) {
- return mRootTaskLeash;
- } else if (getTaskId1() == taskId) {
- return mTaskLeash1;
- } else if (getTaskId2() == taskId) {
- return mTaskLeash2;
- } else {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- if (mRootTaskInfo != null) {
- pw.println(innerPrefix + "Root taskId=" + mRootTaskInfo.taskId
- + " winMode=" + mRootTaskInfo.getWindowingMode());
- }
- if (mTaskInfo1 != null) {
- pw.println(innerPrefix + "1 taskId=" + mTaskInfo1.taskId
- + " winMode=" + mTaskInfo1.getWindowingMode());
- }
- if (mTaskInfo2 != null) {
- pw.println(innerPrefix + "2 taskId=" + mTaskInfo2.taskId
- + " winMode=" + mTaskInfo2.getWindowingMode());
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + getRootTaskId();
- }
-
- @Override
- public void onSnappedToDismiss(boolean snappedToEnd) {
- unpair(snappedToEnd ? mTaskInfo1.token : mTaskInfo2.token /* toTopToken */);
- }
-
- @Override
- public void onLayoutPositionChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- true /* applyResizingOffset */));
- }
-
- @Override
- public void onLayoutSizeChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- true /* applyResizingOffset */));
- }
-
- @Override
- public void onLayoutSizeChanged(SplitLayout layout) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t ->
- layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2,
- false /* applyResizingOffset */));
- }
-
- @Override
- public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
- mController.getTaskOrganizer().applyTransaction(wct);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
deleted file mode 100644
index a9b1dbc3c23b..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
+++ /dev/null
@@ -1,38 +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.apppairs;
-
-import android.app.ActivityManager;
-
-import androidx.annotation.NonNull;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-import java.io.PrintWriter;
-
-/**
- * Interface to engage app pairs feature.
- */
-@ExternalThread
-public interface AppPairs {
- /** Pairs indicated tasks. */
- boolean pair(int task1, int task2);
- /** Pairs indicated tasks. */
- boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2);
- /** Unpairs any app-pair containing this task id. */
- void unpair(int taskId);
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
deleted file mode 100644
index 53234ab971d6..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ /dev/null
@@ -1,213 +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.apppairs;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-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 java.io.PrintWriter;
-
-/**
- * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
- */
-public class AppPairsController {
- private static final String TAG = AppPairsController.class.getSimpleName();
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final SyncTransactionQueue mSyncQueue;
- private final ShellExecutor mMainExecutor;
- private final AppPairsImpl mImpl = new AppPairsImpl();
-
- private AppPairsPool mPairsPool;
- // Active app-pairs mapped by root task id key.
- private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
- private final DisplayController mDisplayController;
- private final DisplayImeController mDisplayImeController;
- private final DisplayInsetsController mDisplayInsetsController;
-
- public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController, ShellExecutor mainExecutor,
- DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController) {
- mTaskOrganizer = organizer;
- mSyncQueue = syncQueue;
- mDisplayController = displayController;
- mDisplayImeController = displayImeController;
- mDisplayInsetsController = displayInsetsController;
- mMainExecutor = mainExecutor;
- }
-
- public AppPairs asAppPairs() {
- return mImpl;
- }
-
- public void onOrganizerRegistered() {
- if (mPairsPool == null) {
- setPairsPool(new AppPairsPool(this));
- }
- }
-
- @VisibleForTesting
- public void setPairsPool(AppPairsPool pool) {
- mPairsPool = pool;
- }
-
- public boolean pair(int taskId1, int taskId2) {
- final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
- final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
- if (task1 == null || task2 == null) {
- return false;
- }
- return pair(task1, task2);
- }
-
- public boolean pair(ActivityManager.RunningTaskInfo task1,
- ActivityManager.RunningTaskInfo task2) {
- return pairInner(task1, task2) != null;
- }
-
- @VisibleForTesting
- public AppPair pairInner(
- @NonNull ActivityManager.RunningTaskInfo task1,
- @NonNull ActivityManager.RunningTaskInfo task2) {
- final AppPair pair = mPairsPool.acquire();
- if (!pair.pair(task1, task2)) {
- mPairsPool.release(pair);
- return null;
- }
-
- mActiveAppPairs.put(pair.getRootTaskId(), pair);
- return pair;
- }
-
- public void unpair(int taskId) {
- unpair(taskId, true /* releaseToPool */);
- }
-
- public void unpair(int taskId, boolean releaseToPool) {
- AppPair pair = mActiveAppPairs.get(taskId);
- if (pair == null) {
- for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
- final AppPair candidate = mActiveAppPairs.valueAt(i);
- if (candidate.contains(taskId)) {
- pair = candidate;
- break;
- }
- }
- }
- if (pair == null) {
- ProtoLog.v(WM_SHELL_TASK_ORG, "taskId %d isn't isn't in an app-pair.", taskId);
- return;
- }
-
- ProtoLog.v(WM_SHELL_TASK_ORG, "unpair taskId=%d pair=%s", taskId, pair);
- mActiveAppPairs.remove(pair.getRootTaskId());
- pair.unpair();
- if (releaseToPool) {
- mPairsPool.release(pair);
- }
- }
-
- ShellTaskOrganizer getTaskOrganizer() {
- return mTaskOrganizer;
- }
-
- SyncTransactionQueue getSyncTransactionQueue() {
- return mSyncQueue;
- }
-
- DisplayController getDisplayController() {
- return mDisplayController;
- }
-
- DisplayImeController getDisplayImeController() {
- return mDisplayImeController;
- }
-
- DisplayInsetsController getDisplayInsetsController() {
- return mDisplayInsetsController;
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
-
- for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
- mActiveAppPairs.valueAt(i).dump(pw, childPrefix);
- }
-
- if (mPairsPool != null) {
- mPairsPool.dump(pw, prefix);
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + mActiveAppPairs.size();
- }
-
- private class AppPairsImpl implements AppPairs {
- @Override
- public boolean pair(int task1, int task2) {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = AppPairsController.this.pair(task1, task2);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
- }
- return result[0];
- }
-
- @Override
- public boolean pair(ActivityManager.RunningTaskInfo task1,
- ActivityManager.RunningTaskInfo task2) {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = AppPairsController.this.pair(task1, task2);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to pair tasks: " + task1 + ", " + task2);
- }
- return result[0];
- }
-
- @Override
- public void unpair(int taskId) {
- mMainExecutor.execute(() -> {
- AppPairsController.this.unpair(taskId);
- });
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
deleted file mode 100644
index 5c6037ea0702..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
+++ /dev/null
@@ -1,93 +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.apppairs;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * Class that manager pool of {@link AppPair} objects. Helps reduce the need to call system_server
- * to create a root task for the app-pair when needed since we always have one ready to go.
- */
-class AppPairsPool {
- private static final String TAG = AppPairsPool.class.getSimpleName();
-
- @VisibleForTesting
- final AppPairsController mController;
- // The pool
- private final ArrayList<AppPair> mPool = new ArrayList();
-
- AppPairsPool(AppPairsController controller) {
- mController = controller;
- incrementPool();
- }
-
- AppPair acquire() {
- final AppPair entry = mPool.remove(mPool.size() - 1);
- ProtoLog.v(WM_SHELL_TASK_ORG, "acquire entry.taskId=%s listener=%s size=%d",
- entry.getRootTaskId(), entry, mPool.size());
- if (mPool.size() == 0) {
- incrementPool();
- }
- return entry;
- }
-
- void release(AppPair entry) {
- mPool.add(entry);
- ProtoLog.v(WM_SHELL_TASK_ORG, "release entry.taskId=%s listener=%s size=%d",
- entry.getRootTaskId(), entry, mPool.size());
- }
-
- @VisibleForTesting
- void incrementPool() {
- ProtoLog.v(WM_SHELL_TASK_ORG, "incrementPool size=%d", mPool.size());
- final AppPair entry = new AppPair(mController);
- // TODO: multi-display...
- mController.getTaskOrganizer().createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, entry);
- mPool.add(entry);
- }
-
- @VisibleForTesting
- int poolSize() {
- return mPool.size();
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- for (int i = mPool.size() - 1; i >= 0; --i) {
- mPool.get(i).dump(pw, childPrefix);
- }
- }
-
- @Override
- public String toString() {
- return TAG + "#" + mPool.size();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
deleted file mode 100644
index 4d9b520e3f0e..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# WM shell sub-modules apppair owner
-chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 7760df17a8cd..a4b8f37f7b9a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -67,13 +67,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
SETTING_VALUE_ON) != SETTING_VALUE_OFF;
private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
- private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
+
/**
* Max duration to wait for a transition to finish before accepting another gesture start
* request.
*/
private static final long MAX_TRANSITION_DURATION = 2000;
+ private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
+
/**
* Location of the initial touch event of the back gesture.
*/
@@ -105,6 +107,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private final Runnable mResetTransitionRunnable = () -> {
finishAnimation();
mTransitionInProgress = false;
+ ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Transition didn't finish in %d ms. Resetting...",
+ MAX_TRANSITION_DURATION);
};
public BackAnimationController(
@@ -286,8 +290,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mBackGestureStarted = true;
try {
- boolean requestAnimation = mEnableAnimations.get();
- mBackNavigationInfo = mActivityTaskManager.startBackNavigation(requestAnimation);
+ mBackNavigationInfo = mActivityTaskManager.startBackNavigation();
onBackNavigationInfoReceived(mBackNavigationInfo);
} catch (RemoteException remoteException) {
Log.e(TAG, "Failed to initAnimation", remoteException);
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 f427a2c4bc95..ea3712ba34b4 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
@@ -25,6 +25,7 @@ import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOTTOM;
@@ -79,7 +80,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.window.WindowContainerTransaction;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -90,7 +90,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
@@ -435,17 +434,13 @@ public class BubbleController {
});
mDisplayController.addDisplayChangingController(
- new DisplayChangeController.OnDisplayChangingListener() {
- @Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction t) {
- // This is triggered right before the rotation is applied
- if (fromRotation != toRotation) {
- if (mStackView != null) {
- // Layout listener set on stackView will update the positioner
- // once the rotation is applied
- mStackView.onOrientationChanged();
- }
+ (displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
+ // This is triggered right before the rotation is applied
+ if (fromRotation != toRotation) {
+ if (mStackView != null) {
+ // Layout listener set on stackView will update the positioner
+ // once the rotation is applied
+ mStackView.onOrientationChanged();
}
}
});
@@ -885,6 +880,19 @@ public class BubbleController {
}
}
+ private void onNotificationPanelExpandedChanged(boolean expanded) {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "onNotificationPanelExpandedChanged: expanded=" + expanded);
+ }
+ if (mStackView != null && mStackView.isExpanded()) {
+ if (expanded) {
+ mStackView.stopMonitoringSwipeUpGesture();
+ } else {
+ mStackView.startMonitoringSwipeUpGesture();
+ }
+ }
+ }
+
private void setSysuiProxy(Bubbles.SysuiProxy proxy) {
mSysuiProxy = proxy;
}
@@ -1468,6 +1476,18 @@ public class BubbleController {
}
/**
+ * Check if notification panel is in an expanded state.
+ * Makes a call to System UI process and delivers the result via {@code callback} on the
+ * WM Shell main thread.
+ *
+ * @param callback callback that has the result of notification panel expanded state
+ */
+ public void isNotificationPanelExpanded(Consumer<Boolean> callback) {
+ mSysuiProxy.isNotificationPanelExpand(expanded ->
+ mMainExecutor.execute(() -> callback.accept(expanded)));
+ }
+
+ /**
* Description of current bubble state.
*/
private void dump(PrintWriter pw, String[] args) {
@@ -1546,7 +1566,7 @@ public class BubbleController {
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mBubblePositioner.setImeVisible(imeVisible, imeHeight);
if (mStackView != null) {
- mStackView.animateForIme(imeVisible);
+ mStackView.setImeVisible(imeVisible);
}
}
}
@@ -1843,6 +1863,12 @@ public class BubbleController {
}
@Override
+ public void onNotificationPanelExpandedChanged(boolean expanded) {
+ mMainExecutor.execute(
+ () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
+ }
+
+ @Override
public void dump(PrintWriter pw, String[] args) {
try {
mMainExecutor.executeBlocking(() -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index dc2ace949f0c..dce6b56261ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -46,6 +46,9 @@ public class BubbleDebugConfig {
static final boolean DEBUG_OVERFLOW = false;
static final boolean DEBUG_USER_EDUCATION = false;
static final boolean DEBUG_POSITIONER = false;
+ public static final boolean DEBUG_COLLAPSE_ANIMATOR = false;
+ static final boolean DEBUG_BUBBLE_GESTURE = false;
+ public static boolean DEBUG_EXPANDED_VIEW_DRAGGING = false;
private static final boolean FORCE_SHOW_USER_EDUCATION = false;
private static final String FORCE_SHOW_USER_EDUCATION_SETTING =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index b8bf1a8e497e..1b75d8bdb3cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -43,10 +43,13 @@ import android.graphics.CornerPathEffect;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Picture;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -75,6 +78,48 @@ import java.io.PrintWriter;
public class BubbleExpandedView extends LinearLayout {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
+ /** {@link IntProperty} for updating bottom clip */
+ public static final IntProperty<BubbleExpandedView> BOTTOM_CLIP_PROPERTY =
+ new IntProperty<BubbleExpandedView>("bottomClip") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, int value) {
+ expandedView.setBottomClip(value);
+ }
+
+ @Override
+ public Integer get(BubbleExpandedView expandedView) {
+ return expandedView.mBottomClip;
+ }
+ };
+
+ /** {@link FloatProperty} for updating taskView or overflow alpha */
+ public static final FloatProperty<BubbleExpandedView> CONTENT_ALPHA =
+ new FloatProperty<BubbleExpandedView>("contentAlpha") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, float value) {
+ expandedView.setContentAlpha(value);
+ }
+
+ @Override
+ public Float get(BubbleExpandedView expandedView) {
+ return expandedView.getContentAlpha();
+ }
+ };
+
+ /** {@link FloatProperty} for updating manage button alpha */
+ public static final FloatProperty<BubbleExpandedView> MANAGE_BUTTON_ALPHA =
+ new FloatProperty<BubbleExpandedView>("manageButtonAlpha") {
+ @Override
+ public void setValue(BubbleExpandedView expandedView, float value) {
+ expandedView.mManageButton.setAlpha(value);
+ }
+
+ @Override
+ public Float get(BubbleExpandedView expandedView) {
+ return expandedView.mManageButton.getAlpha();
+ }
+ };
+
// The triangle pointing to the expanded view
private View mPointerView;
@Nullable private int[] mExpandedViewContainerLocation;
@@ -90,7 +135,7 @@ public class BubbleExpandedView extends LinearLayout {
/**
* Whether we want the {@code TaskView}'s content to be visible (alpha = 1f). If
- * {@link #mIsAlphaAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
+ * {@link #mIsAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
* value until the animation ends.
*/
private boolean mIsContentVisible = false;
@@ -99,12 +144,13 @@ public class BubbleExpandedView extends LinearLayout {
* Whether we're animating the {@code TaskView}'s alpha value. If so, we will hold off on
* applying alpha changes from {@link #setContentVisibility} until the animation ends.
*/
- private boolean mIsAlphaAnimating = false;
+ private boolean mIsAnimating = false;
private int mPointerWidth;
private int mPointerHeight;
private float mPointerRadius;
private float mPointerOverlap;
+ private final PointF mPointerPos = new PointF();
private CornerPathEffect mPointerEffect;
private ShapeDrawable mCurrentPointer;
private ShapeDrawable mTopPointer;
@@ -113,11 +159,13 @@ public class BubbleExpandedView extends LinearLayout {
private float mCornerRadius = 0f;
private int mBackgroundColorFloating;
private boolean mUsingMaxHeight;
-
+ private int mTopClip = 0;
+ private int mBottomClip = 0;
@Nullable private Bubble mBubble;
private PendingIntent mPendingIntent;
// TODO(b/170891664): Don't use a flag, set the BubbleOverflow object instead
private boolean mIsOverflow;
+ private boolean mIsClipping;
private BubbleController mController;
private BubbleStackView mStackView;
@@ -268,7 +316,8 @@ public class BubbleExpandedView extends LinearLayout {
mExpandedViewContainer.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
+ Rect clip = new Rect(0, mTopClip, view.getWidth(), view.getHeight() - mBottomClip);
+ outline.setRoundRect(clip, mCornerRadius);
}
});
mExpandedViewContainer.setClipToOutline(true);
@@ -300,9 +349,9 @@ public class BubbleExpandedView extends LinearLayout {
// they should not collapse the stack (which all other touches on areas around the AV
// would do).
if (motionEvent.getRawY() >= avBounds.top
- && motionEvent.getRawY() <= avBounds.bottom
- && (motionEvent.getRawX() < avBounds.left
- || motionEvent.getRawX() > avBounds.right)) {
+ && motionEvent.getRawY() <= avBounds.bottom
+ && (motionEvent.getRawX() < avBounds.left
+ || motionEvent.getRawX() > avBounds.right)) {
return true;
}
@@ -384,7 +433,7 @@ public class BubbleExpandedView extends LinearLayout {
}
void applyThemeAttrs() {
- final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
@@ -429,7 +478,7 @@ public class BubbleExpandedView extends LinearLayout {
* ordering surfaces during animations. When content is drawn on top of the app (e.g. bubble
* being dragged out, the manage menu) this is set to false, otherwise it should be true.
*/
- void setSurfaceZOrderedOnTop(boolean onTop) {
+ public void setSurfaceZOrderedOnTop(boolean onTop) {
if (mTaskView == null) {
return;
}
@@ -510,12 +559,12 @@ public class BubbleExpandedView extends LinearLayout {
}
/**
- * Whether we are currently animating the {@code TaskView}'s alpha value. If this is set to
+ * Whether we are currently animating the {@code TaskView}. If this is set to
* true, calls to {@link #setContentVisibility} will not be applied until this is set to false
* again.
*/
- void setAlphaAnimating(boolean animating) {
- mIsAlphaAnimating = animating;
+ public void setAnimating(boolean animating) {
+ mIsAnimating = animating;
// If we're done animating, apply the correct
if (!animating) {
@@ -524,15 +573,128 @@ public class BubbleExpandedView extends LinearLayout {
}
/**
- * Sets the alpha of the underlying {@code TaskView}, since changing the expanded view's alpha
- * does not affect the {@code TaskView} since it uses a Surface.
+ * Get alpha from underlying {@code TaskView} if this view is for a bubble.
+ * Or get alpha for the overflow view if this view is for overflow.
+ *
+ * @return alpha for the content being shown
*/
- void setTaskViewAlpha(float alpha) {
+ public float getContentAlpha() {
+ if (mIsOverflow) {
+ return mOverflowView.getAlpha();
+ }
if (mTaskView != null) {
+ return mTaskView.getAlpha();
+ }
+ return 1f;
+ }
+
+ /**
+ * Set alpha of the underlying {@code TaskView} if this view is for a bubble.
+ * Or set alpha for the overflow view if this view is for overflow.
+ *
+ * Changing expanded view's alpha does not affect the {@code TaskView} since it uses a Surface.
+ */
+ public void setContentAlpha(float alpha) {
+ if (mIsOverflow) {
+ mOverflowView.setAlpha(alpha);
+ } else if (mTaskView != null) {
mTaskView.setAlpha(alpha);
}
- mPointerView.setAlpha(alpha);
- setAlpha(alpha);
+ }
+
+ /**
+ * Set translation Y for the expanded view content.
+ * Excludes manage button and pointer.
+ */
+ public void setContentTranslationY(float translationY) {
+ mExpandedViewContainer.setTranslationY(translationY);
+
+ // Left or right pointer can become detached when moving the view up
+ if (translationY <= 0 && (isShowingLeftPointer() || isShowingRightPointer())) {
+ // Y coordinate where the pointer would start to get detached from the expanded view.
+ // Takes into account bottom clipping and rounded corners
+ float detachPoint =
+ mExpandedViewContainer.getBottom() - mBottomClip - mCornerRadius + translationY;
+ float pointerBottom = mPointerPos.y + mPointerHeight;
+ // If pointer bottom is past detach point, move it in by that many pixels
+ float horizontalShift = 0;
+ if (pointerBottom > detachPoint) {
+ horizontalShift = pointerBottom - detachPoint;
+ }
+ if (isShowingLeftPointer()) {
+ // Move left pointer right
+ movePointerBy(horizontalShift, 0);
+ } else {
+ // Move right pointer left
+ movePointerBy(-horizontalShift, 0);
+ }
+ // Hide pointer if it is moved by entire width
+ mPointerView.setVisibility(
+ horizontalShift > mPointerWidth ? View.INVISIBLE : View.VISIBLE);
+ }
+ }
+
+ /**
+ * Update alpha value for the manage button
+ */
+ public void setManageButtonAlpha(float alpha) {
+ mManageButton.setAlpha(alpha);
+ }
+
+ /**
+ * Set {@link #setTranslationY(float) translationY} for the manage button
+ */
+ public void setManageButtonTranslationY(float translationY) {
+ mManageButton.setTranslationY(translationY);
+ }
+
+ /**
+ * Set top clipping for the view
+ */
+ public void setTopClip(int clip) {
+ mTopClip = clip;
+ onContainerClipUpdate();
+ }
+
+ /**
+ * Set bottom clipping for the view
+ */
+ public void setBottomClip(int clip) {
+ mBottomClip = clip;
+ onContainerClipUpdate();
+ }
+
+ private void onContainerClipUpdate() {
+ if (mTopClip == 0 && mBottomClip == 0) {
+ if (mIsClipping) {
+ mIsClipping = false;
+ if (mTaskView != null) {
+ mTaskView.setClipBounds(null);
+ mTaskView.setEnableSurfaceClipping(false);
+ }
+ mExpandedViewContainer.invalidateOutline();
+ }
+ } else {
+ if (!mIsClipping) {
+ mIsClipping = true;
+ if (mTaskView != null) {
+ mTaskView.setEnableSurfaceClipping(true);
+ }
+ }
+ mExpandedViewContainer.invalidateOutline();
+ if (mTaskView != null) {
+ mTaskView.setClipBounds(new Rect(0, mTopClip, mTaskView.getWidth(),
+ mTaskView.getHeight() - mBottomClip));
+ }
+ }
+ }
+
+ /**
+ * Move pointer from base position
+ */
+ public void movePointerBy(float x, float y) {
+ mPointerView.setTranslationX(mPointerPos.x + x);
+ mPointerView.setTranslationY(mPointerPos.y + y);
}
/**
@@ -543,13 +705,13 @@ public class BubbleExpandedView extends LinearLayout {
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the contents in transparent.
*/
- void setContentVisibility(boolean visibility) {
+ public void setContentVisibility(boolean visibility) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "setContentVisibility: visibility=" + visibility
+ " bubble=" + getBubbleKey());
}
mIsContentVisible = visibility;
- if (mTaskView != null && !mIsAlphaAnimating) {
+ if (mTaskView != null && !mIsAnimating) {
mTaskView.setAlpha(visibility ? 1f : 0f);
mPointerView.setAlpha(visibility ? 1f : 0f);
}
@@ -560,6 +722,44 @@ public class BubbleExpandedView extends LinearLayout {
return mTaskView;
}
+ @VisibleForTesting
+ public BubbleOverflowContainerView getOverflow() {
+ return mOverflowView;
+ }
+
+
+ /**
+ * Return content height: taskView or overflow.
+ * Takes into account clippings set by {@link #setTopClip(int)} and {@link #setBottomClip(int)}
+ *
+ * @return if bubble is for overflow, return overflow height, otherwise return taskView height
+ */
+ public int getContentHeight() {
+ if (mIsOverflow) {
+ return mOverflowView.getHeight() - mTopClip - mBottomClip;
+ }
+ if (mTaskView != null) {
+ return mTaskView.getHeight() - mTopClip - mBottomClip;
+ }
+ return 0;
+ }
+
+ /**
+ * Return bottom position of the content on screen
+ *
+ * @return if bubble is for overflow, return value for overflow, otherwise taskView
+ */
+ public int getContentBottomOnScreen() {
+ Rect out = new Rect();
+ if (mIsOverflow) {
+ mOverflowView.getBoundsOnScreen(out);
+ }
+ if (mTaskView != null) {
+ mTaskView.getBoundsOnScreen(out);
+ }
+ return out.bottom;
+ }
+
int getTaskId() {
return mTaskId;
}
@@ -687,7 +887,9 @@ public class BubbleExpandedView extends LinearLayout {
mTaskView.onLocationChanged();
}
if (mIsOverflow) {
- mOverflowView.show();
+ post(() -> {
+ mOverflowView.show();
+ });
}
}
@@ -730,38 +932,59 @@ public class BubbleExpandedView extends LinearLayout {
post(() -> {
mCurrentPointer = showVertically ? onLeft ? mLeftPointer : mRightPointer : mTopPointer;
updatePointerView();
- float pointerY;
- float pointerX;
if (showVertically) {
- pointerY = bubbleCenter - (mPointerWidth / 2f);
+ mPointerPos.y = bubbleCenter - (mPointerWidth / 2f);
if (!isRtl) {
- pointerX = onLeft
+ mPointerPos.x = onLeft
? -mPointerHeight + mPointerOverlap
: getWidth() - mPaddingRight - mPointerOverlap;
} else {
- pointerX = onLeft
+ mPointerPos.x = onLeft
? -(getWidth() - mPaddingLeft - mPointerOverlap)
: mPointerHeight - mPointerOverlap;
}
} else {
- pointerY = mPointerOverlap;
+ mPointerPos.y = mPointerOverlap;
if (!isRtl) {
- pointerX = bubbleCenter - (mPointerWidth / 2f);
+ mPointerPos.x = bubbleCenter - (mPointerWidth / 2f);
} else {
- pointerX = -(getWidth() - mPaddingLeft - bubbleCenter) + (mPointerWidth / 2f);
+ mPointerPos.x = -(getWidth() - mPaddingLeft - bubbleCenter)
+ + (mPointerWidth / 2f);
}
}
if (animate) {
- mPointerView.animate().translationX(pointerX).translationY(pointerY).start();
+ mPointerView.animate().translationX(mPointerPos.x).translationY(
+ mPointerPos.y).start();
} else {
- mPointerView.setTranslationY(pointerY);
- mPointerView.setTranslationX(pointerX);
+ mPointerView.setTranslationY(mPointerPos.y);
+ mPointerView.setTranslationX(mPointerPos.x);
mPointerView.setVisibility(VISIBLE);
}
});
}
/**
+ * Return true if pointer is shown on the left
+ */
+ public boolean isShowingLeftPointer() {
+ return mCurrentPointer == mLeftPointer;
+ }
+
+ /**
+ * Return true if pointer is shown on the right
+ */
+ public boolean isShowingRightPointer() {
+ return mCurrentPointer == mRightPointer;
+ }
+
+ /**
+ * Return width of the current pointer
+ */
+ public int getPointerWidth() {
+ return mPointerWidth;
+ }
+
+ /**
* Position of the manage button displayed in the expanded view. Used for placing user
* education about the manage button.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index fcd0ed7308ef..9aa285fff19c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -167,7 +167,10 @@ public class BubbleOverflowContainerView extends LinearLayout {
void updateOverflow() {
Resources res = getResources();
- final int columns = res.getInteger(R.integer.bubbles_overflow_columns);
+ int columns = (int) Math.round(getWidth()
+ / (res.getDimension(R.dimen.bubble_name_width)));
+ columns = columns > 0 ? columns : res.getInteger(R.integer.bubbles_overflow_columns);
+
mRecyclerView.setLayoutManager(
new OverflowGridLayoutManager(getContext(), columns));
if (mRecyclerView.getItemDecorationCount() == 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index e9729e45731b..dbad5df9cf56 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
@@ -28,7 +30,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.Surface;
-import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
@@ -366,6 +367,14 @@ public class BubblePositioner {
return mImeVisible ? mImeHeight : 0;
}
+ /** Return top position of the IME if it's visible */
+ public int getImeTop() {
+ if (mImeVisible) {
+ return getScreenRect().bottom - getImeHeight() - getInsets().bottom;
+ }
+ return 0;
+ }
+
/** Sets whether the IME is visible. **/
public void setImeVisible(boolean visible, int height) {
mImeVisible = visible;
@@ -557,16 +566,30 @@ public class BubblePositioner {
* @return the position of the bubble on-screen when the stack is expanded.
*/
public PointF getExpandedBubbleXY(int index, BubbleStackView.StackViewState state) {
- final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles);
+ boolean showBubblesVertically = showBubblesVertically();
+ boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
+
+ int onScreenIndex;
+ if (showBubblesVertically || !isRtl) {
+ onScreenIndex = index;
+ } else {
+ // If bubbles are shown horizontally, check if RTL language is used.
+ // If RTL is active, position first bubble on the right and last on the left.
+ // Last bubble has screen index 0 and first bubble has max screen index value.
+ onScreenIndex = state.numberOfBubbles - 1 - index;
+ }
+
+ final float positionInRow = onScreenIndex * (mBubbleSize + mSpacingBetweenBubbles);
final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles);
- final float centerPosition = showBubblesVertically()
+ final float centerPosition = showBubblesVertically
? mPositionRect.centerY()
: mPositionRect.centerX();
// alignment - centered on the edge
final float rowStart = centerPosition - (expandedStackSize / 2f);
float x;
float y;
- if (showBubblesVertically()) {
+ if (showBubblesVertically) {
int inset = mExpandedViewLargeScreenInsetClosestEdge;
y = rowStart + positionInRow;
int left = mIsLargeScreen
@@ -583,8 +606,8 @@ public class BubblePositioner {
x = rowStart + positionInRow;
}
- if (showBubblesVertically() && mImeVisible) {
- return new PointF(x, getExpandedBubbleYForIme(index, state));
+ if (showBubblesVertically && mImeVisible) {
+ return new PointF(x, getExpandedBubbleYForIme(onScreenIndex, state));
}
return new PointF(x, y);
}
@@ -693,7 +716,7 @@ public class BubblePositioner {
// Start on the left if we're in LTR, right otherwise.
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
- != View.LAYOUT_DIRECTION_RTL;
+ != LAYOUT_DIRECTION_RTL;
final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
R.dimen.bubble_stack_starting_offset_y);
// TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
@@ -749,4 +772,21 @@ public class BubblePositioner {
public void setPinnedLocation(PointF point) {
mPinLocation = point;
}
+
+ /**
+ * Navigation bar has an area where system gestures can be started from.
+ *
+ * @return {@link Rect} for system navigation bar gesture zone
+ */
+ public Rect getNavBarGestureZone() {
+ // Gesture zone height from the bottom
+ int gestureZoneHeight = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_gesture_height);
+ Rect screen = getScreenRect();
+ return new Rect(
+ screen.left,
+ screen.bottom - gestureZoneHeight,
+ screen.right,
+ screen.bottom);
+ }
}
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 0e8dc63943a6..33a5fa12a4a1 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
@@ -21,6 +21,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -44,6 +45,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -56,6 +58,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
+import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.FrameLayout;
@@ -75,8 +78,12 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationController;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerImpl;
+import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerStub;
import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -97,6 +104,12 @@ import java.util.stream.Collectors;
*/
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ /**
+ * Set to {@code true} to enable home gesture handling in bubbles
+ */
+ public static final boolean HOME_GESTURE_ENABLED =
+ SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", false);
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
@@ -148,7 +161,7 @@ public class BubbleStackView extends FrameLayout
* Handler to use for all delayed animations - this way, we can easily cancel them before
* starting a new animation.
*/
- private final ShellExecutor mDelayedAnimationExecutor;
+ private final ShellExecutor mMainExecutor;
private Runnable mDelayedAnimation;
/**
@@ -197,6 +210,7 @@ public class BubbleStackView extends FrameLayout
private PhysicsAnimationLayout mBubbleContainer;
private StackAnimationController mStackAnimationController;
private ExpandedAnimationController mExpandedAnimationController;
+ private ExpandedViewAnimationController mExpandedViewAnimationController;
private View mScrim;
private View mManageMenuScrim;
@@ -276,6 +290,9 @@ public class BubbleStackView extends FrameLayout
*/
private int mPointerIndexDown = -1;
+ @Nullable
+ private BubblesNavBarGestureTracker mBubblesNavBarGestureTracker;
+
/** Description of current animation controller state. */
public void dump(PrintWriter pw, String[] args) {
pw.println("Stack view state:");
@@ -693,6 +710,67 @@ public class BubbleStackView extends FrameLayout
}
};
+ /** Touch listener set on the whole view that forwards event to the swipe up listener. */
+ private final RelativeTouchListener mContainerSwipeListener = new RelativeTouchListener() {
+ @Override
+ public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) {
+ // Pass move event on to swipe listener
+ mSwipeUpListener.onDown(ev.getX(), ev.getY());
+ return true;
+ }
+
+ @Override
+ public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
+ float viewInitialY, float dx, float dy) {
+ // Pass move event on to swipe listener
+ mSwipeUpListener.onMove(dx, dy);
+ }
+
+ @Override
+ public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
+ float viewInitialY, float dx, float dy, float velX, float velY) {
+ // Pass up even on to swipe listener
+ mSwipeUpListener.onUp(velX, velY);
+ }
+ };
+
+ /** MotionEventListener that listens from home gesture swipe event. */
+ private final MotionEventListener mSwipeUpListener = new MotionEventListener() {
+ @Override
+ public void onDown(float x, float y) {}
+
+ @Override
+ public void onMove(float dx, float dy) {
+ if ((mManageEduView != null && mManageEduView.getVisibility() == VISIBLE)
+ || isStackEduShowing()) {
+ return;
+ }
+
+ if (mShowingManage) {
+ showManageMenu(false /* show */);
+ }
+ // Only allow up
+ float collapsed = Math.min(dy, 0);
+ mExpandedViewAnimationController.updateDrag((int) -collapsed);
+ }
+
+ @Override
+ public void onCancel() {
+ mExpandedViewAnimationController.animateBackToExpanded();
+ }
+
+ @Override
+ public void onUp(float velX, float velY) {
+ mExpandedViewAnimationController.setSwipeVelocity(velY);
+ if (mExpandedViewAnimationController.shouldCollapse()) {
+ // Update data first and start the animation when we are processing change
+ mBubbleData.setExpanded(false);
+ } else {
+ mExpandedViewAnimationController.animateBackToExpanded();
+ }
+ }
+ };
+
/** Click listener set on the flyout, which expands the stack when the flyout is tapped. */
private OnClickListener mFlyoutClickListener = new OnClickListener() {
@Override
@@ -766,7 +844,7 @@ public class BubbleStackView extends FrameLayout
ShellExecutor mainExecutor) {
super(context);
- mDelayedAnimationExecutor = mainExecutor;
+ mMainExecutor = mainExecutor;
mBubbleController = bubbleController;
mBubbleData = data;
@@ -796,6 +874,14 @@ public class BubbleStackView extends FrameLayout
mExpandedAnimationController = new ExpandedAnimationController(mPositioner,
onBubbleAnimatedOut, this);
+
+ if (HOME_GESTURE_ENABLED) {
+ mExpandedViewAnimationController =
+ new ExpandedViewAnimationControllerImpl(context, mPositioner);
+ } else {
+ mExpandedViewAnimationController = new ExpandedViewAnimationControllerStub();
+ }
+
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
@@ -971,7 +1057,7 @@ public class BubbleStackView extends FrameLayout
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
// We need to be Z ordered on top in order for alpha animations to work.
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
- mExpandedBubble.getExpandedView().setAlphaAnimating(true);
+ mExpandedBubble.getExpandedView().setAnimating(true);
}
}
@@ -985,14 +1071,15 @@ public class BubbleStackView extends FrameLayout
// = 0f remains in effect.
&& !mExpandedViewTemporarilyHidden) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
- mExpandedBubble.getExpandedView().setAlphaAnimating(false);
+ mExpandedBubble.getExpandedView().setAnimating(false);
}
}
});
mExpandedViewAlphaAnimator.addUpdateListener(valueAnimator -> {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setTaskViewAlpha(
- (float) valueAnimator.getAnimatedValue());
+ float alpha = (float) valueAnimator.getAnimatedValue();
+ mExpandedBubble.getExpandedView().setContentAlpha(alpha);
+ mExpandedBubble.getExpandedView().setAlpha(alpha);
}
});
@@ -1795,6 +1882,7 @@ public class BubbleStackView extends FrameLayout
private void showNewlySelectedBubble(BubbleViewProvider bubbleToSelect) {
final BubbleViewProvider previouslySelected = mExpandedBubble;
mExpandedBubble = bubbleToSelect;
+ mExpandedViewAnimationController.setExpandedView(mExpandedBubble.getExpandedView());
if (mIsExpanded) {
hideCurrentInputMethod();
@@ -1843,12 +1931,19 @@ public class BubbleStackView extends FrameLayout
return;
}
+ boolean wasExpanded = mIsExpanded;
+
hideCurrentInputMethod();
mBubbleController.getSysuiProxy().onStackExpandChanged(shouldExpand);
- if (mIsExpanded) {
- animateCollapse();
+ if (wasExpanded) {
+ stopMonitoringSwipeUpGesture();
+ if (HOME_GESTURE_ENABLED) {
+ animateCollapse();
+ } else {
+ animateCollapseWithScale();
+ }
logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
} else {
animateExpansion();
@@ -1856,11 +1951,58 @@ public class BubbleStackView extends FrameLayout
logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
logBubbleEvent(mExpandedBubble,
FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
+ if (HOME_GESTURE_ENABLED) {
+ mBubbleController.isNotificationPanelExpanded(notifPanelExpanded -> {
+ if (!notifPanelExpanded && mIsExpanded) {
+ startMonitoringSwipeUpGesture();
+ }
+ });
+ }
}
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
/**
+ * Monitor for swipe up gesture that is used to collapse expanded view
+ */
+ void startMonitoringSwipeUpGesture() {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "startMonitoringSwipeUpGesture");
+ }
+ stopMonitoringSwipeUpGestureInternal();
+
+ if (isGestureNavEnabled()) {
+ mBubblesNavBarGestureTracker = new BubblesNavBarGestureTracker(mContext, mPositioner);
+ mBubblesNavBarGestureTracker.start(mSwipeUpListener);
+ setOnTouchListener(mContainerSwipeListener);
+ }
+ }
+
+ private boolean isGestureNavEnabled() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode)
+ == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+ }
+
+ /**
+ * Stop monitoring for swipe up gesture
+ */
+ void stopMonitoringSwipeUpGesture() {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "stopMonitoringSwipeUpGesture");
+ }
+ stopMonitoringSwipeUpGestureInternal();
+ }
+
+ private void stopMonitoringSwipeUpGestureInternal() {
+ if (mBubblesNavBarGestureTracker != null) {
+ mBubblesNavBarGestureTracker.stop();
+ mBubblesNavBarGestureTracker = null;
+ setOnTouchListener(null);
+ }
+ }
+
+ /**
* Called when back press occurs while bubbles are expanded.
*/
public void onBackPressed() {
@@ -2072,11 +2214,12 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
if (mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().setTaskViewAlpha(0f);
+ mExpandedBubble.getExpandedView().setContentAlpha(0f);
+ mExpandedBubble.getExpandedView().setAlpha(0f);
// We'll be starting the alpha animation after a slight delay, so set this flag early
// here.
- mExpandedBubble.getExpandedView().setAlphaAnimating(true);
+ mExpandedBubble.getExpandedView().setAnimating(true);
}
mDelayedAnimation = () -> {
@@ -2114,10 +2257,10 @@ public class BubbleStackView extends FrameLayout
})
.start();
};
- mDelayedAnimationExecutor.executeDelayed(mDelayedAnimation, startDelay);
+ mMainExecutor.executeDelayed(mDelayedAnimation, startDelay);
}
- private void animateCollapse() {
+ private void animateCollapseWithScale() {
cancelDelayedExpandCollapseSwitchAnimations();
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
@@ -2217,6 +2360,68 @@ public class BubbleStackView extends FrameLayout
.start();
}
+ private void animateCollapse() {
+ cancelDelayedExpandCollapseSwitchAnimations();
+
+ if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+ mManageEduView.hide();
+ }
+
+ mIsExpanded = false;
+ mIsExpansionAnimating = true;
+
+ showScrim(false);
+
+ mBubbleContainer.cancelAllAnimations();
+
+ // If we were in the middle of swapping, the animating-out surface would have been scaling
+ // to zero - finish it off.
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+ mAnimatingOutSurfaceContainer.setScaleX(0f);
+ mAnimatingOutSurfaceContainer.setScaleY(0f);
+
+ // Let the expanded animation controller know that it shouldn't animate child adds/reorders
+ // since we're about to animate collapsed.
+ mExpandedAnimationController.notifyPreparingToCollapse();
+
+ final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController
+ .getStackPositionAlongNearestHorizontalEdge()
+ /* collapseTo */,
+ () -> mBubbleContainer.setActiveController(mStackAnimationController));
+
+ final Runnable after = () -> {
+ final BubbleViewProvider previouslySelected = mExpandedBubble;
+ // TODO(b/231350255): investigate why this call is needed here
+ beforeExpandedViewAnimation();
+ if (mManageEduView != null) {
+ mManageEduView.hide();
+ }
+
+ if (DEBUG_BUBBLE_STACK_VIEW) {
+ Log.d(TAG, "animateCollapse");
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
+ mExpandedBubble));
+ }
+ updateOverflowVisibility();
+ updateZOrder();
+ updateBadges(true /* setBadgeForCollapsedStack */);
+ afterExpandedViewAnimation();
+ if (previouslySelected != null) {
+ previouslySelected.setTaskViewVisibility(false);
+ }
+ mExpandedViewAnimationController.reset();
+ };
+ mExpandedViewAnimationController.animateCollapse(collapseBackToStack, after);
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // When the animation completes, we should no longer be showing the content.
+ // This won't actually update content visibility immediately, if we are currently
+ // animating. But updates the internal state for the content to be hidden after
+ // animation completes.
+ mExpandedBubble.getExpandedView().setContentVisibility(false);
+ }
+ }
+
private void animateSwitchBubbles() {
// If we're no longer expanded, this is meaningless.
if (!mIsExpanded) {
@@ -2278,7 +2483,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- mDelayedAnimationExecutor.executeDelayed(() -> {
+ mMainExecutor.executeDelayed(() -> {
if (!mIsExpanded) {
mIsBubbleSwitchAnimating = false;
return;
@@ -2309,7 +2514,7 @@ public class BubbleStackView extends FrameLayout
* animating flags for those animations.
*/
private void cancelDelayedExpandCollapseSwitchAnimations() {
- mDelayedAnimationExecutor.removeCallbacks(mDelayedAnimation);
+ mMainExecutor.removeCallbacks(mDelayedAnimation);
mIsExpansionAnimating = false;
mIsBubbleSwitchAnimating = false;
@@ -2333,9 +2538,18 @@ public class BubbleStackView extends FrameLayout
/**
* Updates the stack based for IME changes. When collapsed it'll move the stack if it
* overlaps where they IME would be. When expanded it'll shift the expanded bubbles
- * if they might overlap with the IME (this only happens for large screens).
+ * if they might overlap with the IME (this only happens for large screens)
+ * and clip the expanded view.
*/
- public void animateForIme(boolean visible) {
+ public void setImeVisible(boolean visible) {
+ if (HOME_GESTURE_ENABLED) {
+ setImeVisibleInternal(visible);
+ } else {
+ setImeVisibleWithoutClipping(visible);
+ }
+ }
+
+ private void setImeVisibleWithoutClipping(boolean visible) {
if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) {
// This will update the animation so the bubbles move to position for the IME
mExpandedAnimationController.expandFromStack(() -> {
@@ -2386,6 +2600,62 @@ public class BubbleStackView extends FrameLayout
}
}
+ private void setImeVisibleInternal(boolean visible) {
+ if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) {
+ // This will update the animation so the bubbles move to position for the IME
+ mExpandedAnimationController.expandFromStack(() -> {
+ updatePointerPosition(false /* forIme */);
+ afterExpandedViewAnimation();
+ mExpandedViewAnimationController.animateForImeVisibilityChange(visible);
+ } /* after */);
+ return;
+ }
+
+ if (!mIsExpanded && getBubbleCount() > 0) {
+ final float stackDestinationY =
+ mStackAnimationController.animateForImeVisibility(visible);
+
+ // How far the stack is animating due to IME, we'll just animate the flyout by that
+ // much too.
+ final float stackDy =
+ stackDestinationY - mStackAnimationController.getStackPosition().y;
+
+ // If the flyout is visible, translate it along with the bubble stack.
+ if (mFlyout.getVisibility() == VISIBLE) {
+ PhysicsAnimator.getInstance(mFlyout)
+ .spring(DynamicAnimation.TRANSLATION_Y,
+ mFlyout.getTranslationY() + stackDy,
+ FLYOUT_IME_ANIMATION_SPRING_CONFIG)
+ .start();
+ }
+ }
+
+ if (mIsExpanded) {
+ mExpandedViewAnimationController.animateForImeVisibilityChange(visible);
+ if (mPositioner.showBubblesVertically()
+ && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ float selectedY = mPositioner.getExpandedBubbleXY(getState().selectedIndex,
+ getState()).y;
+ float newExpandedViewTop = mPositioner.getExpandedViewY(mExpandedBubble, selectedY);
+ mExpandedBubble.getExpandedView().setImeVisible(visible);
+ if (!mExpandedBubble.getExpandedView().isUsingMaxHeight()) {
+ mExpandedViewContainer.animate().translationY(newExpandedViewTop);
+ }
+ List<Animator> animList = new ArrayList();
+ for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
+ View child = mBubbleContainer.getChildAt(i);
+ float transY = mPositioner.getExpandedBubbleXY(i, getState()).y;
+ ObjectAnimator anim = ObjectAnimator.ofFloat(child, TRANSLATION_Y, transY);
+ animList.add(anim);
+ }
+ updatePointerPosition(true /* forIme */);
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animList);
+ set.start();
+ }
+ }
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() != MotionEvent.ACTION_DOWN && ev.getActionIndex() != mPointerIndexDown) {
@@ -2821,7 +3091,7 @@ public class BubbleStackView extends FrameLayout
&& mExpandedBubble.getExpandedView() != null) {
BubbleExpandedView bev = mExpandedBubble.getExpandedView();
bev.setContentVisibility(false);
- bev.setAlphaAnimating(!mIsExpansionAnimating);
+ bev.setAnimating(!mIsExpansionAnimating);
mExpandedViewContainerMatrix.setScaleX(0f);
mExpandedViewContainerMatrix.setScaleY(0f);
mExpandedViewContainerMatrix.setTranslate(0f, 0f);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 8a0db0a12711..0072da19b9ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -214,6 +214,11 @@ public interface Bubbles {
int modificationType);
/**
+ * Called when notification panel is expanded or collapsed
+ */
+ void onNotificationPanelExpandedChanged(boolean expanded);
+
+ /**
* Called when the status bar has become visible or invisible (either permanently or
* temporarily).
*/
@@ -285,7 +290,7 @@ public interface Bubbles {
/** Callback to tell SysUi components execute some methods. */
interface SysuiProxy {
- void isNotificationShadeExpand(Consumer<Boolean> callback);
+ void isNotificationPanelExpand(Consumer<Boolean> callback);
void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
new file mode 100644
index 000000000000..e7beeeb06534
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 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.bubbles;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.InputChannel;
+import android.view.InputEventReceiver;
+import android.view.InputMonitor;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
+
+/**
+ * Set up tracking bubbles gestures that begin in navigation bar
+ */
+class BubblesNavBarGestureTracker {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BubblesGestureTracker" : TAG_BUBBLES;
+
+ private static final String GESTURE_MONITOR = "bubbles-gesture";
+ private final Context mContext;
+ private final BubblePositioner mPositioner;
+
+ @Nullable
+ private InputMonitor mInputMonitor;
+ @Nullable
+ private InputEventReceiver mInputEventReceiver;
+
+ BubblesNavBarGestureTracker(Context context, BubblePositioner positioner) {
+ mContext = context;
+ mPositioner = positioner;
+ }
+
+ /**
+ * Start tracking gestures
+ *
+ * @param listener listener that is notified of touch events
+ */
+ void start(MotionEventListener listener) {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "start monitoring bubbles swipe up gesture");
+ }
+
+ stopInternal();
+
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(GESTURE_MONITOR,
+ mContext.getDisplayId());
+ InputChannel inputChannel = mInputMonitor.getInputChannel();
+
+ BubblesNavBarMotionEventHandler motionEventHandler =
+ new BubblesNavBarMotionEventHandler(mContext, mPositioner,
+ this::onInterceptTouch, listener);
+ mInputEventReceiver = new BubblesNavBarInputEventReceiver(inputChannel,
+ Choreographer.getInstance(), motionEventHandler);
+ }
+
+ void stop() {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "stop monitoring bubbles swipe up gesture");
+ }
+ stopInternal();
+ }
+
+ private void stopInternal() {
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
+ if (mInputMonitor != null) {
+ mInputMonitor.dispose();
+ mInputMonitor = null;
+ }
+ }
+
+ private void onInterceptTouch() {
+ if (BubbleDebugConfig.DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "intercept touch event");
+ }
+ if (mInputMonitor != null) {
+ mInputMonitor.pilferPointers();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java
new file mode 100644
index 000000000000..45037b87830f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarInputEventReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.bubbles;
+
+import android.os.Looper;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+
+/**
+ * Bubbles {@link BatchedInputEventReceiver} for monitoring touches from navbar gesture area
+ */
+class BubblesNavBarInputEventReceiver extends BatchedInputEventReceiver {
+
+ private final BubblesNavBarMotionEventHandler mMotionEventHandler;
+
+ BubblesNavBarInputEventReceiver(InputChannel inputChannel,
+ Choreographer choreographer, BubblesNavBarMotionEventHandler motionEventHandler) {
+ super(inputChannel, Looper.myLooper(), choreographer);
+ mMotionEventHandler = motionEventHandler;
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = false;
+ try {
+ if (!(event instanceof MotionEvent)) {
+ return;
+ }
+ handled = mMotionEventHandler.onMotionEvent((MotionEvent) event);
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
new file mode 100644
index 000000000000..844526ca0f35
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2022 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.bubbles;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Handles {@link MotionEvent}s for bubbles that begin in the nav bar area
+ */
+class BubblesNavBarMotionEventHandler {
+ private static final String TAG =
+ TAG_WITH_CLASS_NAME ? "BubblesNavBarMotionEventHandler" : TAG_BUBBLES;
+ private static final int VELOCITY_UNITS = 1000;
+
+ private final Runnable mOnInterceptTouch;
+ private final MotionEventListener mMotionEventListener;
+ private final int mTouchSlop;
+ private final BubblePositioner mPositioner;
+ private final PointF mTouchDown = new PointF();
+ private boolean mTrackingTouches;
+ private boolean mInterceptingTouches;
+ @Nullable
+ private VelocityTracker mVelocityTracker;
+
+ BubblesNavBarMotionEventHandler(Context context, BubblePositioner positioner,
+ Runnable onInterceptTouch, MotionEventListener motionEventListener) {
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mPositioner = positioner;
+ mOnInterceptTouch = onInterceptTouch;
+ mMotionEventListener = motionEventListener;
+ }
+
+ /**
+ * Handle {@link MotionEvent} and forward it to {@code motionEventListener} defined in
+ * constructor
+ *
+ * @return {@code true} if this {@link MotionEvent} is handled (it started in the gesture area)
+ */
+ public boolean onMotionEvent(MotionEvent motionEvent) {
+ float dx = motionEvent.getX() - mTouchDown.x;
+ float dy = motionEvent.getY() - mTouchDown.y;
+
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (isInGestureRegion(motionEvent)) {
+ mTouchDown.set(motionEvent.getX(), motionEvent.getY());
+ mMotionEventListener.onDown(motionEvent.getX(), motionEvent.getY());
+ mTrackingTouches = true;
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mTrackingTouches) {
+ if (!mInterceptingTouches && Math.hypot(dx, dy) > mTouchSlop) {
+ mInterceptingTouches = true;
+ mOnInterceptTouch.run();
+ }
+ if (mInterceptingTouches) {
+ getVelocityTracker().addMovement(motionEvent);
+ mMotionEventListener.onMove(dx, dy);
+ }
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ if (mTrackingTouches) {
+ mMotionEventListener.onCancel();
+ finishTracking();
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mTrackingTouches) {
+ if (mInterceptingTouches) {
+ getVelocityTracker().computeCurrentVelocity(VELOCITY_UNITS);
+ mMotionEventListener.onUp(getVelocityTracker().getXVelocity(),
+ getVelocityTracker().getYVelocity());
+ }
+ finishTracking();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ private boolean isInGestureRegion(MotionEvent ev) {
+ // Only handles touch events beginning in navigation bar system gesture zone
+ if (mPositioner.getNavBarGestureZone().contains((int) ev.getX(), (int) ev.getY())) {
+ if (DEBUG_BUBBLE_GESTURE) {
+ Log.d(TAG, "handling touch y=" + ev.getY()
+ + " navBarGestureZone=" + mPositioner.getNavBarGestureZone());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private VelocityTracker getVelocityTracker() {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ return mVelocityTracker;
+ }
+
+ private void finishTracking() {
+ mTouchDown.set(0, 0);
+ mTrackingTouches = false;
+ mInterceptingTouches = false;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+
+ /**
+ * Callback for receiving {@link MotionEvent} updates
+ */
+ interface MotionEventListener {
+ /**
+ * Touch down action.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+ void onDown(float x, float y);
+
+ /**
+ * Move action.
+ * Reports distance from point reported in {@link #onDown(float, float)}
+ *
+ * @param dx distance moved on x-axis from starting point, in pixels
+ * @param dy distance moved on y-axis from starting point, in pixels
+ */
+ void onMove(float dx, float dy);
+
+ /**
+ * Touch up action.
+ *
+ * @param velX velocity of the move action on x axis
+ * @param velY velocity of the move actin on y axis
+ */
+ void onUp(float velX, float velY);
+
+ /**
+ * Motion action was cancelled.
+ */
+ void onCancel();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index cf0cefec401a..ea9d065d5f53 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -17,8 +17,6 @@
package com.android.wm.shell.bubbles
import android.graphics.PointF
-import android.os.Handler
-import android.os.Looper
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
@@ -146,6 +144,12 @@ abstract class RelativeTouchListener : View.OnTouchListener {
velocityTracker.clear()
movedEnough = false
}
+
+ MotionEvent.ACTION_CANCEL -> {
+ v.handler.removeCallbacksAndMessages(null)
+ velocityTracker.clear()
+ movedEnough = false
+ }
}
return true
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 573f42468512..b521cb6a3d38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -16,12 +16,16 @@
package com.android.wm.shell.bubbles.animation;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
+import static com.android.wm.shell.bubbles.BubbleStackView.HOME_GESTURE_ENABLED;
import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.PointF;
import android.view.View;
+import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -61,7 +65,10 @@ public class ExpandedAnimationController
private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f;
/** Stiffness for the expand/collapse path-following animation. */
- private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
+ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400;
+
+ /** Stiffness for the expand/collapse animation when home gesture handling is off */
+ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS_WITHOUT_HOME_GESTURE = 1000;
/**
* Velocity required to dismiss an individual bubble without dragging it into the dismiss
@@ -73,6 +80,11 @@ public class ExpandedAnimationController
new PhysicsAnimator.SpringConfig(
EXPAND_COLLAPSE_ANIM_STIFFNESS, SpringForce.DAMPING_RATIO_NO_BOUNCY);
+ private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfigWithoutHomeGesture =
+ new PhysicsAnimator.SpringConfig(
+ EXPAND_COLLAPSE_ANIM_STIFFNESS_WITHOUT_HOME_GESTURE,
+ SpringForce.DAMPING_RATIO_NO_BOUNCY);
+
/** Horizontal offset between bubbles, which we need to know to re-stack them. */
private float mStackOffsetPx;
/** Size of each bubble. */
@@ -233,6 +245,11 @@ public class ExpandedAnimationController
};
}
+ boolean showBubblesVertically = mPositioner.showBubblesVertically();
+ final boolean isRtl =
+ mLayout.getContext().getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
+
// Animate each bubble individually, since each path will end in a different spot.
animationsForChildrenFromIndex(0, (index, animation) -> {
final View bubble = mLayout.getChildAt(index);
@@ -267,9 +284,20 @@ public class ExpandedAnimationController
// right side, the first bubble is traveling to the top left, so it leads. During
// collapse to the left, the first bubble has the shortest travel time back to the stack
// position, so it leads (and vice versa).
- final boolean firstBubbleLeads =
- (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
+ final boolean firstBubbleLeads;
+ if (showBubblesVertically || !isRtl) {
+ firstBubbleLeads =
+ (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
|| (!expanding && mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x));
+ } else {
+ // For RTL languages, when showing bubbles horizontally, it is reversed. The bubbles
+ // are positioned right to left. This means that when expanding from left, the top
+ // bubble will lead as it will be positioned on the right. And when expanding from
+ // right, the top bubble will have the least travel distance.
+ firstBubbleLeads =
+ (expanding && mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
+ || (!expanding && !mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x));
+ }
final int startDelay = firstBubbleLeads
? (index * 10)
: ((mLayout.getChildCount() - index) * 10);
@@ -278,11 +306,20 @@ public class ExpandedAnimationController
(firstBubbleLeads && index == 0)
|| (!firstBubbleLeads && index == mLayout.getChildCount() - 1);
+ Interpolator interpolator;
+ if (HOME_GESTURE_ENABLED) {
+ // When home gesture is enabled, we use a different animation timing for collapse
+ interpolator = expanding
+ ? Interpolators.EMPHASIZED_ACCELERATE : Interpolators.EMPHASIZED_DECELERATE;
+ } else {
+ interpolator = Interpolators.LINEAR;
+ }
+
animation
.followAnimatedTargetAlongPath(
path,
EXPAND_COLLAPSE_TARGET_ANIM_DURATION /* targetAnimDuration */,
- Interpolators.LINEAR /* targetAnimInterpolator */,
+ interpolator /* targetAnimInterpolator */,
isLeadBubble ? mLeadBubbleEndAction : null /* endAction */,
() -> mLeadBubbleEndAction = null /* endAction */)
.withStartDelay(startDelay)
@@ -525,10 +562,16 @@ public class ExpandedAnimationController
finishRemoval.run();
mOnBubbleAnimatedOutAction.run();
} else {
+ PhysicsAnimator.SpringConfig springConfig;
+ if (HOME_GESTURE_ENABLED) {
+ springConfig = mAnimateOutSpringConfig;
+ } else {
+ springConfig = mAnimateOutSpringConfigWithoutHomeGesture;
+ }
PhysicsAnimator.getInstance(child)
.spring(DynamicAnimation.ALPHA, 0f)
- .spring(DynamicAnimation.SCALE_X, 0f, mAnimateOutSpringConfig)
- .spring(DynamicAnimation.SCALE_Y, 0f, mAnimateOutSpringConfig)
+ .spring(DynamicAnimation.SCALE_X, 0f, springConfig)
+ .spring(DynamicAnimation.SCALE_Y, 0f, springConfig)
.withEndActions(finishRemoval, mOnBubbleAnimatedOutAction)
.start();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java
new file mode 100644
index 000000000000..8a33780bc8d5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationController.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 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.bubbles.animation;
+
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+
+/**
+ * Animation controller for bubble expanded view collapsing
+ */
+public interface ExpandedViewAnimationController {
+ /**
+ * Set expanded view that this controller is working with.
+ */
+ void setExpandedView(BubbleExpandedView expandedView);
+
+ /**
+ * Set current collapse value, in pixels.
+ *
+ * @param distance pixels that user dragged the view by
+ */
+ void updateDrag(float distance);
+
+ /**
+ * Set current swipe velocity.
+ * Velocity is directional:
+ * <ul>
+ * <li>velocity < 0 means swipe direction is up</li>
+ * <li>velocity > 0 means swipe direction is down</li>
+ * </ul>
+ */
+ void setSwipeVelocity(float velocity);
+
+ /**
+ * Check if view is dragged past collapse threshold or swipe up velocity exceeds min velocity
+ * required to collapse the view
+ */
+ boolean shouldCollapse();
+
+ /**
+ * Animate view to collapsed state
+ *
+ * @param startStackCollapse runnable that is triggered when bubbles can start moving back to
+ * their collapsed location
+ * @param after runnable to run after animation is complete
+ */
+ void animateCollapse(Runnable startStackCollapse, Runnable after);
+
+ /**
+ * Animate the view back to fully expanded state.
+ */
+ void animateBackToExpanded();
+
+ /**
+ * Animate view for IME visibility change
+ */
+ void animateForImeVisibilityChange(boolean visible);
+
+ /**
+ * Reset the view to fully expanded state
+ */
+ void reset();
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
new file mode 100644
index 000000000000..ca54232c95b5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2022 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.bubbles.animation;
+
+import static android.view.View.ALPHA;
+
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_COLLAPSE_ANIMATOR;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_EXPANDED_VIEW_DRAGGING;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.BOTTOM_CLIP_PROPERTY;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.CONTENT_ALPHA;
+import static com.android.wm.shell.bubbles.BubbleExpandedView.MANAGE_BUTTON_ALPHA;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.wm.shell.animation.FlingAnimationUtils;
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+import com.android.wm.shell.bubbles.BubblePositioner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of {@link ExpandedViewAnimationController} that uses a collapse animation to
+ * hide the {@link BubbleExpandedView}
+ */
+public class ExpandedViewAnimationControllerImpl implements ExpandedViewAnimationController {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ExpandedViewAnimCtrl" : TAG_BUBBLES;
+
+ private static final float COLLAPSE_THRESHOLD = 0.02f;
+
+ private static final int COLLAPSE_DURATION_MS = 250;
+
+ private static final int MANAGE_BUTTON_ANIM_DURATION_MS = 78;
+
+ private static final int CONTENT_OPACITY_ANIM_DELAY_MS = 93;
+ private static final int CONTENT_OPACITY_ANIM_DURATION_MS = 78;
+
+ private static final int BACKGROUND_OPACITY_ANIM_DELAY_MS = 172;
+ private static final int BACKGROUND_OPACITY_ANIM_DURATION_MS = 78;
+
+ /** Animation fraction threshold for content alpha animation when stack collapse should begin */
+ private static final float STACK_COLLAPSE_THRESHOLD = 0.5f;
+
+ private static final FloatPropertyCompat<ExpandedViewAnimationControllerImpl>
+ COLLAPSE_HEIGHT_PROPERTY =
+ new FloatPropertyCompat<ExpandedViewAnimationControllerImpl>("CollapseSpring") {
+ @Override
+ public float getValue(ExpandedViewAnimationControllerImpl controller) {
+ return controller.getCollapsedAmount();
+ }
+
+ @Override
+ public void setValue(ExpandedViewAnimationControllerImpl controller,
+ float value) {
+ controller.setCollapsedAmount(value);
+ }
+ };
+
+ private final int mMinFlingVelocity;
+ private float mSwipeUpVelocity;
+ private float mSwipeDownVelocity;
+ private final BubblePositioner mPositioner;
+ private final FlingAnimationUtils mFlingAnimationUtils;
+ private int mDraggedAmount;
+ private float mCollapsedAmount;
+ @Nullable
+ private BubbleExpandedView mExpandedView;
+ @Nullable
+ private AnimatorSet mCollapseAnimation;
+ private boolean mNotifiedAboutThreshold;
+ private SpringAnimation mBackToExpandedAnimation;
+ @Nullable
+ private ObjectAnimator mBottomClipAnim;
+
+ public ExpandedViewAnimationControllerImpl(Context context, BubblePositioner positioner) {
+ mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
+ COLLAPSE_DURATION_MS / 1000f);
+ mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
+ mPositioner = positioner;
+ }
+
+ private static void adjustAnimatorSetDuration(AnimatorSet animatorSet,
+ float durationAdjustment) {
+ for (Animator animator : animatorSet.getChildAnimations()) {
+ animator.setStartDelay((long) (animator.getStartDelay() * durationAdjustment));
+ animator.setDuration((long) (animator.getDuration() * durationAdjustment));
+ }
+ }
+
+ @Override
+ public void setExpandedView(BubbleExpandedView expandedView) {
+ if (mExpandedView != null) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "updating expandedView, resetting previous");
+ }
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ if (mBackToExpandedAnimation != null) {
+ mBackToExpandedAnimation.cancel();
+ }
+ reset();
+ }
+ mExpandedView = expandedView;
+ }
+
+ @Override
+ public void updateDrag(float distance) {
+ if (mExpandedView != null) {
+ mDraggedAmount = OverScroll.dampedScroll(distance, mExpandedView.getContentHeight());
+
+ if (DEBUG_COLLAPSE_ANIMATOR && DEBUG_EXPANDED_VIEW_DRAGGING) {
+ Log.d(TAG, "updateDrag: distance=" + distance + " dragged=" + mDraggedAmount);
+ }
+
+ setCollapsedAmount(mDraggedAmount);
+
+ if (!mNotifiedAboutThreshold && isPastCollapseThreshold()) {
+ mNotifiedAboutThreshold = true;
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "notifying over collapse threshold");
+ }
+ vibrateIfEnabled();
+ }
+ }
+ }
+
+ @Override
+ public void setSwipeVelocity(float velocity) {
+ if (velocity < 0) {
+ mSwipeUpVelocity = Math.abs(velocity);
+ mSwipeDownVelocity = 0;
+ } else {
+ mSwipeUpVelocity = 0;
+ mSwipeDownVelocity = velocity;
+ }
+ }
+
+ @Override
+ public boolean shouldCollapse() {
+ if (mSwipeDownVelocity > mMinFlingVelocity) {
+ // Swipe velocity is positive and over fling velocity.
+ // This is a swipe down, always reset to expanded state, regardless of dragged amount.
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "not collapsing expanded view, swipe down velocity: " + mSwipeDownVelocity
+ + " minV: " + mMinFlingVelocity);
+ }
+ return false;
+ }
+
+ if (mSwipeUpVelocity > mMinFlingVelocity) {
+ // Swiping up and over fling velocity, collapse the view.
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "collapse expanded view, swipe up velocity: " + mSwipeUpVelocity + " minV: "
+ + mMinFlingVelocity);
+ }
+ return true;
+ }
+
+ if (isPastCollapseThreshold()) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "collapse expanded view, past threshold, dragged: " + mDraggedAmount);
+ }
+ return true;
+ }
+
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "not collapsing expanded view");
+ }
+
+ return false;
+ }
+
+ @Override
+ public void animateCollapse(Runnable startStackCollapse, Runnable after) {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG,
+ "expandedView animate collapse swipeVel=" + mSwipeUpVelocity + " minFlingVel="
+ + mMinFlingVelocity);
+ }
+ if (mExpandedView != null) {
+ // Mark it as animating immediately to avoid updates to the view before animation starts
+ mExpandedView.setAnimating(true);
+
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ mCollapseAnimation = createCollapseAnimation(mExpandedView, startStackCollapse, after);
+
+ if (mSwipeUpVelocity >= mMinFlingVelocity) {
+ int contentHeight = mExpandedView.getContentHeight();
+
+ // Use a temp animator to get adjusted duration value for swipe.
+ // This new value will be used to adjust animation times proportionally in the
+ // animator set. If we adjust animator set duration directly, all child animations
+ // will get the same animation time.
+ ValueAnimator tempAnimator = new ValueAnimator();
+ mFlingAnimationUtils.applyDismissing(tempAnimator, mCollapsedAmount, contentHeight,
+ mSwipeUpVelocity, (contentHeight - mCollapsedAmount));
+
+ float durationAdjustment =
+ (float) tempAnimator.getDuration() / COLLAPSE_DURATION_MS;
+
+ adjustAnimatorSetDuration(mCollapseAnimation, durationAdjustment);
+ mCollapseAnimation.setInterpolator(tempAnimator.getInterpolator());
+ }
+ mCollapseAnimation.start();
+ }
+ }
+
+ @Override
+ public void animateBackToExpanded() {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "expandedView animate back to expanded");
+ }
+ BubbleExpandedView expandedView = mExpandedView;
+ if (expandedView == null) {
+ return;
+ }
+
+ expandedView.setAnimating(true);
+
+ mBackToExpandedAnimation = new SpringAnimation(this, COLLAPSE_HEIGHT_PROPERTY);
+ mBackToExpandedAnimation.setSpring(new SpringForce()
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ );
+ mBackToExpandedAnimation.addEndListener(new OneTimeEndListener() {
+ @Override
+ public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
+ float velocity) {
+ super.onAnimationEnd(animation, canceled, value, velocity);
+ mNotifiedAboutThreshold = false;
+ mBackToExpandedAnimation = null;
+ expandedView.setAnimating(false);
+ }
+ });
+ mBackToExpandedAnimation.setStartValue(mCollapsedAmount);
+ mBackToExpandedAnimation.animateToFinalPosition(0);
+ }
+
+ @Override
+ public void animateForImeVisibilityChange(boolean visible) {
+ if (mExpandedView != null) {
+ if (mBottomClipAnim != null) {
+ mBottomClipAnim.cancel();
+ }
+ int clip = 0;
+ if (visible) {
+ // Clip the expanded view at the top of the IME view
+ clip = mExpandedView.getContentBottomOnScreen() - mPositioner.getImeTop();
+ // Don't allow negative clip value
+ clip = Math.max(clip, 0);
+ }
+ mBottomClipAnim = ObjectAnimator.ofInt(mExpandedView, BOTTOM_CLIP_PROPERTY, clip);
+ mBottomClipAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBottomClipAnim = null;
+ }
+ });
+ mBottomClipAnim.start();
+ }
+ }
+
+ @Override
+ public void reset() {
+ if (DEBUG_COLLAPSE_ANIMATOR) {
+ Log.d(TAG, "reset expandedView collapsed state");
+ }
+ if (mExpandedView == null) {
+ return;
+ }
+ mExpandedView.setAnimating(false);
+
+ if (mCollapseAnimation != null) {
+ mCollapseAnimation.cancel();
+ }
+ if (mBackToExpandedAnimation != null) {
+ mBackToExpandedAnimation.cancel();
+ }
+ mExpandedView.setContentAlpha(1);
+ mExpandedView.setAlpha(1);
+ mExpandedView.setManageButtonAlpha(1);
+ setCollapsedAmount(0);
+ mExpandedView.setBottomClip(0);
+ mExpandedView.movePointerBy(0, 0);
+ mCollapsedAmount = 0;
+ mDraggedAmount = 0;
+ mSwipeUpVelocity = 0;
+ mSwipeDownVelocity = 0;
+ mNotifiedAboutThreshold = false;
+ }
+
+ private float getCollapsedAmount() {
+ return mCollapsedAmount;
+ }
+
+ private void setCollapsedAmount(float collapsed) {
+ if (mCollapsedAmount != collapsed) {
+ float previous = mCollapsedAmount;
+ mCollapsedAmount = collapsed;
+
+ if (mExpandedView != null) {
+ if (previous == 0) {
+ // View was not collapsed before. Apply z order change
+ mExpandedView.setSurfaceZOrderedOnTop(true);
+ mExpandedView.setAnimating(true);
+ }
+
+ mExpandedView.setTopClip((int) mCollapsedAmount);
+ // Move up with translationY. Use negative collapsed value
+ mExpandedView.setContentTranslationY(-mCollapsedAmount);
+ mExpandedView.setManageButtonTranslationY(-mCollapsedAmount);
+
+ if (mCollapsedAmount == 0) {
+ // View is no longer collapsed. Revert z order change
+ mExpandedView.setSurfaceZOrderedOnTop(false);
+ mExpandedView.setAnimating(false);
+ }
+ }
+ }
+ }
+
+ private boolean isPastCollapseThreshold() {
+ if (mExpandedView != null) {
+ return mDraggedAmount > mExpandedView.getContentHeight() * COLLAPSE_THRESHOLD;
+ }
+ return false;
+ }
+
+ private AnimatorSet createCollapseAnimation(BubbleExpandedView expandedView,
+ Runnable startStackCollapse, Runnable after) {
+ List<Animator> animatorList = new ArrayList<>();
+ animatorList.add(createHeightAnimation(expandedView));
+ animatorList.add(createManageButtonAnimation());
+ ObjectAnimator contentAlphaAnimation = createContentAlphaAnimation();
+ final boolean[] notified = {false};
+ contentAlphaAnimation.addUpdateListener(animation -> {
+ if (!notified[0] && animation.getAnimatedFraction() > STACK_COLLAPSE_THRESHOLD) {
+ notified[0] = true;
+ // Notify bubbles that they can start moving back to the collapsed position
+ startStackCollapse.run();
+ }
+ });
+ animatorList.add(contentAlphaAnimation);
+ animatorList.add(createBackgroundAlphaAnimation());
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ after.run();
+ }
+ });
+ animatorSet.playTogether(animatorList);
+ return animatorSet;
+ }
+
+ private ValueAnimator createHeightAnimation(BubbleExpandedView expandedView) {
+ ValueAnimator animator = ValueAnimator.ofInt((int) mCollapsedAmount,
+ expandedView.getContentHeight());
+ animator.setInterpolator(Interpolators.EMPHASIZED_ACCELERATE);
+ animator.setDuration(COLLAPSE_DURATION_MS);
+ animator.addUpdateListener(anim -> setCollapsedAmount((int) anim.getAnimatedValue()));
+ return animator;
+ }
+
+ private ObjectAnimator createManageButtonAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, MANAGE_BUTTON_ALPHA, 0f);
+ animator.setDuration(MANAGE_BUTTON_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ return animator;
+ }
+
+ private ObjectAnimator createContentAlphaAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, CONTENT_ALPHA, 0f);
+ animator.setDuration(CONTENT_OPACITY_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.setStartDelay(CONTENT_OPACITY_ANIM_DELAY_MS);
+ return animator;
+ }
+
+ private ObjectAnimator createBackgroundAlphaAnimation() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandedView, ALPHA, 0f);
+ animator.setDuration(BACKGROUND_OPACITY_ANIM_DURATION_MS);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.setStartDelay(BACKGROUND_OPACITY_ANIM_DELAY_MS);
+ return animator;
+ }
+
+ @SuppressLint("MissingPermission")
+ private void vibrateIfEnabled() {
+ if (mExpandedView != null) {
+ mExpandedView.performHapticFeedback(HapticFeedbackConstants.DRAG_CROSSING);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java
new file mode 100644
index 000000000000..bb8a3aaaf551
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.bubbles.animation;
+
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+
+/**
+ * Stub implementation {@link ExpandedViewAnimationController} that does not animate the
+ * {@link BubbleExpandedView}
+ */
+public class ExpandedViewAnimationControllerStub implements ExpandedViewAnimationController {
+ @Override
+ public void setExpandedView(BubbleExpandedView expandedView) {
+ }
+
+ @Override
+ public void updateDrag(float distance) {
+ }
+
+ @Override
+ public void setSwipeVelocity(float velocity) {
+ }
+
+ @Override
+ public boolean shouldCollapse() {
+ return false;
+ }
+
+ @Override
+ public void animateCollapse(Runnable startStackCollapse, Runnable after) {
+ }
+
+ @Override
+ public void animateBackToExpanded() {
+ }
+
+ @Override
+ public void animateForImeVisibilityChange(boolean visible) {
+ }
+
+ @Override
+ public void reset() {
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java
new file mode 100644
index 000000000000..d4e76ed0282e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OverScroll.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.bubbles.animation;
+
+/**
+ * Utility methods for overscroll damping and related effect.
+ *
+ * Copied from packages/apps/Launcher3/src/com/android/launcher3/touch/OverScroll.java
+ */
+public class OverScroll {
+
+ private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+
+ /**
+ * This curve determines how the effect of scrolling over the limits of the page diminishes
+ * as the user pulls further and further from the bounds
+ *
+ * @param f The percentage of how much the user has overscrolled.
+ * @return A transformed percentage based on the influence curve.
+ */
+ private static float overScrollInfluenceCurve(float f) {
+ f -= 1.0f;
+ return f * f * f + 1.0f;
+ }
+
+ /**
+ * @param amount The original amount overscrolled.
+ * @param max The maximum amount that the View can overscroll.
+ * @return The dampened overscroll amount.
+ */
+ public static int dampedScroll(float amount, int max) {
+ if (Float.compare(amount, 0) == 0) return 0;
+
+ float f = amount / max;
+ f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+ // Clamp this factor, f, to -1 < f < 1
+ if (Math.abs(f) >= 1) {
+ f /= Math.abs(f);
+ }
+
+ return Math.round(OVERSCROLL_DAMP_FACTOR * f * max);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index c32733d4f73c..28c7367662a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -16,11 +16,13 @@
package com.android.wm.shell.common;
+import android.annotation.Nullable;
import android.os.RemoteException;
import android.util.Slog;
-import android.view.IDisplayWindowRotationCallback;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowCallback;
+import android.view.IDisplayChangeWindowController;
import android.view.IWindowManager;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
@@ -40,17 +42,17 @@ public class DisplayChangeController {
private final ShellExecutor mMainExecutor;
private final IWindowManager mWmService;
- private final IDisplayWindowRotationController mControllerImpl;
+ private final IDisplayChangeWindowController mControllerImpl;
- private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
+ private final CopyOnWriteArrayList<OnDisplayChangingListener> mDisplayChangeListener =
new CopyOnWriteArrayList<>();
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mWmService = wmService;
- mControllerImpl = new DisplayWindowRotationControllerImpl();
+ mControllerImpl = new DisplayChangeWindowControllerImpl();
try {
- mWmService.setDisplayWindowRotationController(mControllerImpl);
+ mWmService.setDisplayChangeWindowController(mControllerImpl);
} catch (RemoteException e) {
throw new RuntimeException("Unable to register rotation controller");
}
@@ -59,63 +61,64 @@ public class DisplayChangeController {
/**
* Adds a display rotation controller.
*/
- public void addRotationListener(OnDisplayChangingListener listener) {
- mRotationListener.add(listener);
+ public void addDisplayChangeListener(OnDisplayChangingListener listener) {
+ mDisplayChangeListener.add(listener);
}
/**
* Removes a display rotation controller.
*/
- public void removeRotationListener(OnDisplayChangingListener listener) {
- mRotationListener.remove(listener);
+ public void removeDisplayChangeListener(OnDisplayChangingListener listener) {
+ mDisplayChangeListener.remove(listener);
}
- /** Query all listeners for changes that should happen on rotation. */
- public void dispatchOnRotateDisplay(WindowContainerTransaction outWct, int displayId,
- final int fromRotation, final int toRotation) {
- for (OnDisplayChangingListener c : mRotationListener) {
- c.onRotateDisplay(displayId, fromRotation, toRotation, outWct);
+ /** Query all listeners for changes that should happen on display change. */
+ public void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
+ int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) {
+ for (OnDisplayChangingListener c : mDisplayChangeListener) {
+ c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct);
}
}
- private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
- IDisplayWindowRotationCallback callback) {
+ private void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
WindowContainerTransaction t = new WindowContainerTransaction();
- dispatchOnRotateDisplay(t, displayId, fromRotation, toRotation);
+ dispatchOnDisplayChange(t, displayId, fromRotation, toRotation, newDisplayAreaInfo);
try {
- callback.continueRotateDisplay(toRotation, t);
+ callback.continueDisplayChange(t);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to continue rotation", e);
+ Slog.e(TAG, "Failed to continue handling display change", e);
}
}
@BinderThread
- private class DisplayWindowRotationControllerImpl
- extends IDisplayWindowRotationController.Stub {
+ private class DisplayChangeWindowControllerImpl
+ extends IDisplayChangeWindowController.Stub {
@Override
- public void onRotateDisplay(int displayId, final int fromRotation,
- final int toRotation, IDisplayWindowRotationCallback callback) {
- mMainExecutor.execute(() -> {
- DisplayChangeController.this.onRotateDisplay(displayId, fromRotation, toRotation,
- callback);
- });
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
+ mMainExecutor.execute(() -> DisplayChangeController.this
+ .onDisplayChange(displayId, fromRotation, toRotation,
+ newDisplayAreaInfo, callback));
}
}
/**
* Give a listener a chance to queue up configuration changes to execute as part of a
- * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
+ * display rotation. The contents of {@link #onDisplayChange} must run synchronously.
*/
@ShellMainThread
public interface OnDisplayChangingListener {
/**
- * Called before the display is rotated. Contents of this method must run synchronously.
- * @param displayId Id of display that is rotating.
- * @param fromRotation starting rotation of the display.
- * @param toRotation target rotation of the display (after rotating).
+ * Called before the display size has changed.
+ * Contents of this method must run synchronously.
+ * @param displayId display id of the display that is under the change
+ * @param fromRotation rotation before the change
+ * @param toRotation rotation after the change
+ * @param newDisplayAreaInfo display area info after applying the update
* @param t A task transaction to populate.
*/
- void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction t);
+ void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction t);
}
}
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 4ba32e93fb3d..764936cceb01 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
@@ -156,14 +156,14 @@ public class DisplayController {
* Adds a display rotation controller.
*/
public void addDisplayChangingController(OnDisplayChangingListener controller) {
- mChangeController.addRotationListener(controller);
+ mChangeController.addDisplayChangeListener(controller);
}
/**
* Removes a display rotation controller.
*/
public void removeDisplayChangingController(OnDisplayChangingListener controller) {
- mChangeController.removeRotationListener(controller);
+ mChangeController.removeDisplayChangeListener(controller);
}
private void onDisplayAdded(int displayId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index db6131a17114..1d10bbe37438 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -38,8 +38,6 @@ import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.TaskViewFactoryController;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.apppairs.AppPairs;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.back.BackAnimationController;
import com.android.wm.shell.bubbles.BubbleController;
@@ -70,8 +68,6 @@ import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -319,26 +315,27 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static Optional<FullscreenUnfoldController> provideFullscreenUnfoldController(
- @DynamicOverride Optional<FullscreenUnfoldController> fullscreenUnfoldController,
+ @DynamicOverride Lazy<Optional<FullscreenUnfoldController>> fullscreenUnfoldController,
Optional<ShellUnfoldProgressProvider> progressProvider) {
if (progressProvider.isPresent()
&& progressProvider.get() != ShellUnfoldProgressProvider.NO_PROVIDER) {
- return fullscreenUnfoldController;
+ return fullscreenUnfoldController.get();
}
return Optional.empty();
}
+ @BindsOptionalOf
+ @DynamicOverride
+ abstract UnfoldTransitionHandler optionalUnfoldTransitionHandler();
+
@WMSingleton
@Provides
static Optional<UnfoldTransitionHandler> provideUnfoldTransitionHandler(
Optional<ShellUnfoldProgressProvider> progressProvider,
- TransactionPool transactionPool,
- Transitions transitions,
- @ShellMainThread ShellExecutor executor) {
- if (progressProvider.isPresent()) {
- return Optional.of(
- new UnfoldTransitionHandler(progressProvider.get(), transactionPool, executor,
- transitions));
+ @DynamicOverride Lazy<Optional<UnfoldTransitionHandler>> handler) {
+ if (progressProvider.isPresent()
+ && progressProvider.get() != ShellUnfoldProgressProvider.NO_PROVIDER) {
+ return handler.get();
}
return Optional.empty();
}
@@ -561,29 +558,6 @@ public abstract class WMShellBaseModule {
return Optional.empty();
}
- // Legacy split (optional feature)
-
- @WMSingleton
- @Provides
- static Optional<LegacySplitScreen> provideLegacySplitScreen(
- Optional<LegacySplitScreenController> splitScreenController) {
- return splitScreenController.map((controller) -> controller.asLegacySplitScreen());
- }
-
- @BindsOptionalOf
- abstract LegacySplitScreenController optionalLegacySplitScreenController();
-
- // App Pairs (optional feature)
-
- @WMSingleton
- @Provides
- static Optional<AppPairs> provideAppPairs(Optional<AppPairsController> appPairsController) {
- return appPairsController.map((controller) -> controller.asAppPairs());
- }
-
- @BindsOptionalOf
- abstract AppPairsController optionalAppPairs();
-
//
// Starting window
//
@@ -664,7 +638,6 @@ public abstract class WMShellBaseModule {
KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
- Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
@@ -682,7 +655,6 @@ public abstract class WMShellBaseModule {
kidsModeTaskOrganizer,
bubblesOptional,
splitScreenOptional,
- appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
appUnfoldTransitionController,
@@ -709,17 +681,15 @@ public abstract class WMShellBaseModule {
static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
KidsModeTaskOrganizer kidsModeTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
- Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasksOptional,
@ShellMainThread ShellExecutor mainExecutor) {
return new ShellCommandHandlerImpl(shellTaskOrganizer, kidsModeTaskOrganizer,
- legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
- hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
+ splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
+ recentTasksOptional, mainExecutor);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index b3799e2cf8d9..47c9214bcae9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.dagger;
-import android.animation.AnimationHandler;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.os.Handler;
@@ -31,7 +30,6 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -43,13 +41,11 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
@@ -67,6 +63,7 @@ import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
+import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
@@ -75,6 +72,8 @@ import com.android.wm.shell.splitscreen.StageTaskUnfoldController;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import com.android.wm.shell.unfold.UnfoldBackgroundController;
+import com.android.wm.shell.unfold.UnfoldTransitionHandler;
+import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import java.util.Optional;
@@ -182,31 +181,6 @@ public class WMShellModule {
recentTasks, stageTaskUnfoldControllerProvider);
}
- @WMSingleton
- @Provides
- static LegacySplitScreenController provideLegacySplitScreen(Context context,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController displayImeController, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
- TaskStackListenerImpl taskStackListener, Transitions transitions,
- @ShellMainThread ShellExecutor mainExecutor,
- @ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) {
- return new LegacySplitScreenController(context, displayController, systemWindows,
- displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
- taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler);
- }
-
- @WMSingleton
- @Provides
- static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, DisplayController displayController,
- @ShellMainThread ShellExecutor mainExecutor,
- DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController) {
- return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
- mainExecutor, displayImeController, displayInsetsController);
- }
-
//
// Pip
//
@@ -215,7 +189,8 @@ public class WMShellModule {
@Provides
static Optional<Pip> providePip(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -224,7 +199,8 @@ public class WMShellModule {
Optional<OneHandedController> oneHandedController,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(context, displayController,
- pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState,
+ pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
+ pipMotionHelper,
pipMediaController, phonePipMenuController, pipTaskOrganizer,
pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor));
@@ -244,6 +220,12 @@ public class WMShellModule {
@WMSingleton
@Provides
+ static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
+ return new PipKeepClearAlgorithm();
+ }
+
+ @WMSingleton
+ @Provides
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm);
@@ -356,15 +338,37 @@ public class WMShellModule {
@Provides
@DynamicOverride
static FullscreenUnfoldController provideFullscreenUnfoldController(
- Context context,
Optional<ShellUnfoldProgressProvider> progressProvider,
- Lazy<UnfoldBackgroundController> unfoldBackgroundController,
- DisplayInsetsController displayInsetsController,
+ Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
+ FullscreenUnfoldTaskAnimator fullscreenUnfoldTaskAnimator,
+ UnfoldBackgroundController unfoldBackgroundController,
@ShellMainThread ShellExecutor mainExecutor
) {
- return new FullscreenUnfoldController(context, mainExecutor,
- unfoldBackgroundController.get(), progressProvider.get(),
- displayInsetsController);
+ return new FullscreenUnfoldController(mainExecutor,
+ unfoldBackgroundController, progressProvider.get(),
+ unfoldTransitionHandler.get(), fullscreenUnfoldTaskAnimator);
+ }
+
+ @Provides
+ static FullscreenUnfoldTaskAnimator provideFullscreenUnfoldTaskAnimator(
+ Context context,
+ DisplayInsetsController displayInsetsController
+ ) {
+ return new FullscreenUnfoldTaskAnimator(context, displayInsetsController);
+ }
+
+ @WMSingleton
+ @Provides
+ @DynamicOverride
+ static UnfoldTransitionHandler provideUnfoldTransitionHandler(
+ Optional<ShellUnfoldProgressProvider> progressProvider,
+ FullscreenUnfoldTaskAnimator animator,
+ UnfoldBackgroundController backgroundController,
+ TransactionPool transactionPool,
+ Transitions transitions,
+ @ShellMainThread ShellExecutor executor) {
+ return new UnfoldTransitionHandler(progressProvider.get(), animator,
+ transactionPool, backgroundController, executor, transitions);
}
@Provides
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 73e6cba43ec0..1fc1215b6cea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -76,6 +76,8 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
taskInfo.taskId);
final Point positionInParent = taskInfo.positionInParent;
mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent));
+ mAnimatableTasksListener.onTaskAppeared(taskInfo);
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
mSyncQueue.runInSync(t -> {
// Reset several properties back to fullscreen (PiP, for example, leaves all these
@@ -87,15 +89,15 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
t.show(leash);
});
- mAnimatableTasksListener.onTaskAppeared(taskInfo);
updateRecentsForVisibleFullscreenTask(taskInfo);
}
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ mAnimatableTasksListener.onTaskInfoChanged(taskInfo);
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- mAnimatableTasksListener.onTaskInfoChanged(taskInfo);
updateRecentsForVisibleFullscreenTask(taskInfo);
final TaskData data = mDataByTaskId.get(taskInfo.taskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
index aa3868cfca84..99f15f65f74e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
@@ -17,213 +17,119 @@
package com.android.wm.shell.fullscreen;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.util.MathUtils.lerp;
-import static android.view.Display.DEFAULT_DISPLAY;
-import android.animation.RectEvaluator;
-import android.animation.TypeEvaluator;
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.app.TaskInfo;
-import android.content.Context;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.util.SparseArray;
-import android.view.InsetsSource;
-import android.view.InsetsState;
import android.view.SurfaceControl;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
import com.android.wm.shell.unfold.UnfoldBackgroundController;
+import com.android.wm.shell.unfold.UnfoldTransitionHandler;
+import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import java.util.concurrent.Executor;
/**
* Controls full screen app unfold transition: animating cropping window and scaling when
* folding or unfolding a foldable device.
+ *
+ * - When Shell transitions are disabled (legacy mode) this controller animates task surfaces
+ * when doing both fold and unfold.
+ *
+ * - When Shell transitions are enabled this controller animates the surfaces only when
+ * folding a foldable device. It's not done as a shell transition because we are not committed
+ * to the display size WM changes yet.
+ * In this case unfolding is handled by
+ * {@link com.android.wm.shell.unfold.UnfoldTransitionHandler}.
*/
-public final class FullscreenUnfoldController implements UnfoldListener,
- OnInsetsChangedListener {
-
- private static final float[] FLOAT_9 = new float[9];
- private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect());
-
- private static final float HORIZONTAL_START_MARGIN = 0.08f;
- private static final float VERTICAL_START_MARGIN = 0.03f;
- private static final float END_SCALE = 1f;
- private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2;
+public final class FullscreenUnfoldController implements UnfoldListener {
private final Executor mExecutor;
private final ShellUnfoldProgressProvider mProgressProvider;
- private final DisplayInsetsController mDisplayInsetsController;
-
- private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
private final UnfoldBackgroundController mBackgroundController;
-
- private InsetsSource mTaskbarInsetsSource;
-
- private final float mWindowCornerRadiusPx;
- private final float mExpandedTaskBarHeight;
-
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final FullscreenUnfoldTaskAnimator mAnimator;
+ private final UnfoldTransitionHandler mUnfoldTransitionHandler;
+
+ private boolean mShouldHandleAnimation = false;
public FullscreenUnfoldController(
- @NonNull Context context,
@NonNull Executor executor,
@NonNull UnfoldBackgroundController backgroundController,
@NonNull ShellUnfoldProgressProvider progressProvider,
- @NonNull DisplayInsetsController displayInsetsController
+ @NonNull UnfoldTransitionHandler unfoldTransitionHandler,
+ @NonNull FullscreenUnfoldTaskAnimator animator
) {
mExecutor = executor;
mProgressProvider = progressProvider;
- mDisplayInsetsController = displayInsetsController;
- mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.taskbar_frame_height);
mBackgroundController = backgroundController;
+ mUnfoldTransitionHandler = unfoldTransitionHandler;
+ mAnimator = animator;
}
/**
* Initializes the controller
*/
public void init() {
+ mAnimator.init();
mProgressProvider.addListener(mExecutor, this);
- mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this);
+ }
+
+ @Override
+ public void onStateChangeStarted() {
+ mShouldHandleAnimation = !mUnfoldTransitionHandler.willHandleTransition();
}
@Override
public void onStateChangeProgress(float progress) {
- if (mAnimationContextByTaskId.size() == 0) return;
+ if (!mAnimator.hasActiveTasks() || !mShouldHandleAnimation) return;
mBackgroundController.ensureBackground(mTransaction);
-
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
-
- context.mCurrentCropRect.set(RECT_EVALUATOR
- .evaluate(progress, context.mStartCropRect, context.mEndCropRect));
-
- float scale = lerp(START_SCALE, END_SCALE, progress);
- context.mMatrix.setScale(scale, scale, context.mCurrentCropRect.exactCenterX(),
- context.mCurrentCropRect.exactCenterY());
-
- mTransaction.setWindowCrop(context.mLeash, context.mCurrentCropRect)
- .setMatrix(context.mLeash, context.mMatrix, FLOAT_9)
- .setCornerRadius(context.mLeash, mWindowCornerRadiusPx);
- }
-
+ mAnimator.applyAnimationProgress(progress, mTransaction);
mTransaction.apply();
}
@Override
public void onStateChangeFinished() {
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
- resetSurface(context);
+ if (!mShouldHandleAnimation) {
+ return;
}
+ mShouldHandleAnimation = false;
+ mAnimator.resetAllSurfaces(mTransaction);
mBackgroundController.removeBackground(mTransaction);
mTransaction.apply();
}
- @Override
- public void insetsChanged(InsetsState insetsState) {
- mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- AnimationContext context = mAnimationContextByTaskId.valueAt(i);
- context.update(mTaskbarInsetsSource, context.mTaskInfo);
- }
- }
-
/**
* Called when a new matching task appeared
*/
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- AnimationContext animationContext = new AnimationContext(leash, mTaskbarInsetsSource,
- taskInfo);
- mAnimationContextByTaskId.put(taskInfo.taskId, animationContext);
+ mAnimator.addTask(taskInfo, leash);
}
/**
* Called when matching task changed
*/
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
- if (animationContext != null) {
- animationContext.update(mTaskbarInsetsSource, taskInfo);
- }
+ mAnimator.onTaskInfoChanged(taskInfo);
}
/**
* Called when matching task vanished
*/
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
- if (animationContext != null) {
- // PiP task has its own cleanup path, ignore surface reset to avoid conflict.
- if (taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED) {
- resetSurface(animationContext);
- }
- mAnimationContextByTaskId.remove(taskInfo.taskId);
+ // PiP task has its own cleanup path, ignore surface reset to avoid conflict.
+ if (taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ mAnimator.resetSurface(taskInfo, mTransaction);
}
+ mAnimator.removeTask(taskInfo);
- if (mAnimationContextByTaskId.size() == 0) {
+ if (!mAnimator.hasActiveTasks()) {
mBackgroundController.removeBackground(mTransaction);
}
mTransaction.apply();
}
-
- private void resetSurface(AnimationContext context) {
- mTransaction
- .setWindowCrop(context.mLeash, null)
- .setCornerRadius(context.mLeash, 0.0F)
- .setMatrix(context.mLeash, 1.0F, 0.0F, 0.0F, 1.0F)
- .setPosition(context.mLeash,
- (float) context.mTaskInfo.positionInParent.x,
- (float) context.mTaskInfo.positionInParent.y);
- }
-
- private class AnimationContext {
- final SurfaceControl mLeash;
- final Rect mStartCropRect = new Rect();
- final Rect mEndCropRect = new Rect();
- final Rect mCurrentCropRect = new Rect();
- final Matrix mMatrix = new Matrix();
-
- TaskInfo mTaskInfo;
-
- private AnimationContext(SurfaceControl leash,
- InsetsSource taskBarInsetsSource,
- TaskInfo taskInfo) {
- this.mLeash = leash;
- update(taskBarInsetsSource, taskInfo);
- }
-
- private void update(InsetsSource taskBarInsetsSource, TaskInfo taskInfo) {
- mTaskInfo = taskInfo;
- mStartCropRect.set(mTaskInfo.getConfiguration().windowConfiguration.getBounds());
-
- if (taskBarInsetsSource != null) {
- // Only insets the cropping window with task bar when it's expanded
- if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
- mStartCropRect.inset(taskBarInsetsSource
- .calculateVisibleInsets(mStartCropRect));
- }
- }
-
- mEndCropRect.set(mStartCropRect);
-
- int horizontalMargin = (int) (mEndCropRect.width() * HORIZONTAL_START_MARGIN);
- mStartCropRect.left = mEndCropRect.left + horizontalMargin;
- mStartCropRect.right = mEndCropRect.right - horizontalMargin;
- int verticalMargin = (int) (mEndCropRect.height() * VERTICAL_START_MARGIN);
- mStartCropRect.top = mEndCropRect.top + verticalMargin;
- mStartCropRect.bottom = mEndCropRect.bottom - verticalMargin;
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
deleted file mode 100644
index aced072c8c71..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
+++ /dev/null
@@ -1,418 +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.legacysplitscreen;
-
-import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
-import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Choreographer;
-import android.view.SurfaceControl;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TransactionPool;
-
-class DividerImeController implements DisplayImeController.ImePositionProcessor {
- private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
-
- private final LegacySplitScreenTaskListener mSplits;
- private final TransactionPool mTransactionPool;
- private final ShellExecutor mMainExecutor;
- private final TaskOrganizer mTaskOrganizer;
-
- /**
- * These are the y positions of the top of the IME surface when it is hidden and when it is
- * shown respectively. These are NOT necessarily the top of the visible IME itself.
- */
- private int mHiddenTop = 0;
- private int mShownTop = 0;
-
- // The following are target states (what we are curretly animating towards).
- /**
- * {@code true} if, at the end of the animation, the split task positions should be
- * adjusted by height of the IME. This happens when the secondary split is the IME target.
- */
- private boolean mTargetAdjusted = false;
- /**
- * {@code true} if, at the end of the animation, the IME should be shown/visible
- * regardless of what has focus.
- */
- private boolean mTargetShown = false;
- private float mTargetPrimaryDim = 0.f;
- private float mTargetSecondaryDim = 0.f;
-
- // The following are the current (most recent) states set during animation
- /** {@code true} if the secondary split has IME focus. */
- private boolean mSecondaryHasFocus = false;
- /** The dimming currently applied to the primary/secondary splits. */
- private float mLastPrimaryDim = 0.f;
- private float mLastSecondaryDim = 0.f;
- /** The most recent y position of the top of the IME surface */
- private int mLastAdjustTop = -1;
-
- // The following are states reached last time an animation fully completed.
- /** {@code true} if the IME was shown/visible by the last-completed animation. */
- private boolean mImeWasShown = false;
- /** {@code true} if the split positions were adjusted by the last-completed animation. */
- private boolean mAdjusted = false;
-
- /**
- * When some aspect of split-screen needs to animate independent from the IME,
- * this will be non-null and control split animation.
- */
- @Nullable
- private ValueAnimator mAnimation = null;
-
- private boolean mPaused = true;
- private boolean mPausedTargetAdjusted = false;
-
- DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool,
- ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) {
- mSplits = splits;
- mTransactionPool = pool;
- mMainExecutor = mainExecutor;
- mTaskOrganizer = taskOrganizer;
- }
-
- private DividerView getView() {
- return mSplits.mSplitScreenController.getDividerView();
- }
-
- private LegacySplitDisplayLayout getLayout() {
- return mSplits.mSplitScreenController.getSplitLayout();
- }
-
- private boolean isDividerHidden() {
- final DividerView view = mSplits.mSplitScreenController.getDividerView();
- return view == null || view.isHidden();
- }
-
- private boolean getSecondaryHasFocus(int displayId) {
- WindowContainerToken imeSplit = mTaskOrganizer.getImeTarget(displayId);
- return imeSplit != null
- && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
- }
-
- void reset() {
- mPaused = true;
- mPausedTargetAdjusted = false;
- mAnimation = null;
- mAdjusted = mTargetAdjusted = false;
- mImeWasShown = mTargetShown = false;
- mTargetPrimaryDim = mTargetSecondaryDim = mLastPrimaryDim = mLastSecondaryDim = 0.f;
- mSecondaryHasFocus = false;
- mLastAdjustTop = -1;
- }
-
- private void updateDimTargets() {
- final boolean splitIsVisible = !getView().isHidden();
- mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- }
-
-
- @Override
- public void onImeControlTargetChanged(int displayId, boolean controlling) {
- // Restore the split layout when wm-shell is not controlling IME insets anymore.
- if (!controlling && mTargetShown) {
- mPaused = false;
- mTargetAdjusted = mTargetShown = false;
- mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
- updateImeAdjustState(true /* force */);
- startAsyncAnimation();
- }
- }
-
- @Override
- @ImeAnimationFlags
- public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) {
- if (isDividerHidden()) {
- return 0;
- }
- mHiddenTop = hiddenTop;
- mShownTop = shownTop;
- mTargetShown = imeShouldShow;
- mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- final boolean targetAdjusted = imeShouldShow && mSecondaryHasFocus
- && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mSplitScreenController.isMinimized();
- if (mLastAdjustTop < 0) {
- mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
- } else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
- if (mTargetAdjusted != targetAdjusted && targetAdjusted == mAdjusted) {
- // Check for an "interruption" of an existing animation. In this case, we
- // need to fake-flip the last-known state direction so that the animation
- // completes in the other direction.
- mAdjusted = mTargetAdjusted;
- } else if (targetAdjusted && mTargetAdjusted && mAdjusted) {
- // Already fully adjusted for IME, but IME height has changed; so, force-start
- // an async animation to the new IME height.
- mAdjusted = false;
- }
- }
- if (mPaused) {
- mPausedTargetAdjusted = targetAdjusted;
- if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState());
- return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
- }
- mTargetAdjusted = targetAdjusted;
- updateDimTargets();
- if (DEBUG) Slog.d(TAG, " ime starting. " + dumpState());
- if (mAnimation != null || (mImeWasShown && imeShouldShow
- && mTargetAdjusted != mAdjusted)) {
- // We need to animate adjustment independently of the IME position, so
- // start our own animation to drive adjustment. This happens when a
- // different split's editor has gained focus while the IME is still visible.
- startAsyncAnimation();
- }
- updateImeAdjustState();
-
- return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
- }
-
- private void updateImeAdjustState() {
- updateImeAdjustState(false /* force */);
- }
-
- private void updateImeAdjustState(boolean force) {
- if (mAdjusted != mTargetAdjusted || force) {
- // Reposition the server's secondary split position so that it evaluates
- // insets properly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final LegacySplitDisplayLayout splitLayout = getLayout();
- if (mTargetAdjusted) {
- splitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
- wct.setBounds(mSplits.mSecondary.token, splitLayout.mAdjustedSecondary);
- // "Freeze" the configuration size so that the app doesn't get a config
- // or relaunch. This is required because normally nav-bar contributes
- // to configuration bounds (via nondecorframe).
- Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, splitLayout.mAdjustedSecondary.top
- - splitLayout.mSecondary.top);
- wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- mSplits.mSecondary.configuration.screenWidthDp,
- mSplits.mSecondary.configuration.screenHeightDp);
-
- wct.setBounds(mSplits.mPrimary.token, splitLayout.mAdjustedPrimary);
- adjustAppBounds = new Rect(mSplits.mPrimary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, splitLayout.mAdjustedPrimary.top
- - splitLayout.mPrimary.top);
- wct.setAppBounds(mSplits.mPrimary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mPrimary.token,
- mSplits.mPrimary.configuration.screenWidthDp,
- mSplits.mPrimary.configuration.screenHeightDp);
- } else {
- wct.setBounds(mSplits.mSecondary.token, splitLayout.mSecondary);
- wct.setAppBounds(mSplits.mSecondary.token, null);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- wct.setBounds(mSplits.mPrimary.token, splitLayout.mPrimary);
- wct.setAppBounds(mSplits.mPrimary.token, null);
- wct.setScreenSizeDp(mSplits.mPrimary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- }
-
- if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- // Update all the adjusted-for-ime states
- if (!mPaused) {
- final DividerView view = getView();
- if (view != null) {
- view.setAdjustedForIme(mTargetShown, mTargetShown
- ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
- : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
- }
- }
- mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused);
- }
-
- @Override
- public void onImePositionChanged(int displayId, int imeTop,
- SurfaceControl.Transaction t) {
- if (mAnimation != null || isDividerHidden() || mPaused) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetShown ? fraction : 1.f - fraction;
- onProgress(progress, t);
- }
-
- @Override
- public void onImeEndPositioning(int displayId, boolean cancelled,
- SurfaceControl.Transaction t) {
- if (mAnimation != null || isDividerHidden() || mPaused) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- onEnd(cancelled, t);
- }
-
- private void onProgress(float progress, SurfaceControl.Transaction t) {
- final DividerView view = getView();
- if (mTargetAdjusted != mAdjusted && !mPaused) {
- final LegacySplitDisplayLayout splitLayout = getLayout();
- final float fraction = mTargetAdjusted ? progress : 1.f - progress;
- mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
- splitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
- view.resizeSplitSurfaces(t, splitLayout.mAdjustedPrimary,
- splitLayout.mAdjustedSecondary);
- }
- final float invProg = 1.f - progress;
- view.setResizeDimLayer(t, true /* primary */,
- mLastPrimaryDim * invProg + progress * mTargetPrimaryDim);
- view.setResizeDimLayer(t, false /* primary */,
- mLastSecondaryDim * invProg + progress * mTargetSecondaryDim);
- }
-
- void setDimsHidden(SurfaceControl.Transaction t, boolean hidden) {
- final DividerView view = getView();
- if (hidden) {
- view.setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
- view.setResizeDimLayer(t, false /* primary */, 0.f /* alpha */);
- } else {
- updateDimTargets();
- view.setResizeDimLayer(t, true /* primary */, mTargetPrimaryDim);
- view.setResizeDimLayer(t, false /* primary */, mTargetSecondaryDim);
- }
- }
-
- private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
- if (!cancelled) {
- onProgress(1.f, t);
- mAdjusted = mTargetAdjusted;
- mImeWasShown = mTargetShown;
- mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
- mLastPrimaryDim = mTargetPrimaryDim;
- mLastSecondaryDim = mTargetSecondaryDim;
- }
- }
-
- private void startAsyncAnimation() {
- if (mAnimation != null) {
- mAnimation.cancel();
- }
- mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
- mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
- if (mTargetAdjusted != mAdjusted) {
- final float fraction =
- ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
- mAnimation.setCurrentFraction(progress);
- }
-
- mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- float value = (float) animation.getAnimatedValue();
- onProgress(value, t);
- t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
- t.apply();
- mTransactionPool.release(t);
- });
- mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
- mAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancel = false;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancel = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- onEnd(mCancel, t);
- t.apply();
- mTransactionPool.release(t);
- mAnimation = null;
- }
- });
- mAnimation.start();
- }
-
- private String dumpState() {
- return "top:" + mHiddenTop + "->" + mShownTop
- + " adj:" + mAdjusted + "->" + mTargetAdjusted + "(" + mLastAdjustTop + ")"
- + " shw:" + mImeWasShown + "->" + mTargetShown
- + " dims:" + mLastPrimaryDim + "," + mLastSecondaryDim
- + "->" + mTargetPrimaryDim + "," + mTargetSecondaryDim
- + " shf:" + mSecondaryHasFocus + " desync:" + (mAnimation != null)
- + " paus:" + mPaused + "[" + mPausedTargetAdjusted + "]";
- }
-
- /** Completely aborts/resets adjustment state */
- public void pause(int displayId) {
- if (DEBUG) Slog.d(TAG, "ime pause posting " + dumpState());
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "ime pause run posted " + dumpState());
- if (mPaused) {
- return;
- }
- mPaused = true;
- mPausedTargetAdjusted = mTargetAdjusted;
- mTargetAdjusted = false;
- mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
- updateImeAdjustState();
- startAsyncAnimation();
- if (mAnimation != null) {
- mAnimation.end();
- }
- });
- }
-
- public void resume(int displayId) {
- if (DEBUG) Slog.d(TAG, "ime resume posting " + dumpState());
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "ime resume run posted " + dumpState());
- if (!mPaused) {
- return;
- }
- mPaused = false;
- mTargetAdjusted = mPausedTargetAdjusted;
- updateDimTargets();
- final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mSplitScreenController.isMinimized()
- && view != null) {
- // End unminimize animations since they conflict with adjustment animations.
- view.finishAnimations();
- }
- updateImeAdjustState();
- startAsyncAnimation();
- });
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
deleted file mode 100644
index 73be2835d2cd..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ /dev/null
@@ -1,1314 +0,0 @@
-/*
- * Copyright (C) 2015 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.legacysplitscreen;
-
-import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
-import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
-import static android.view.WindowManager.DOCKED_RIGHT;
-
-import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
-import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
-import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
-import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;
-
-import android.animation.AnimationHandler;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.Region.Op;
-import android.hardware.display.DisplayManager;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Choreographer;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver.InternalInsetsInfo;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-import android.widget.FrameLayout;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.wm.shell.R;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.split.DividerHandleView;
-
-import java.util.function.Consumer;
-
-/**
- * Docked stack divider.
- */
-public class DividerView extends FrameLayout implements OnTouchListener,
- OnComputeInternalInsetsListener {
- private static final String TAG = "DividerView";
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- interface DividerCallbacks {
- void onDraggingStart();
- void onDraggingEnd();
- }
-
- public static final int INVALID_RECENTS_GROW_TARGET = -1;
-
- private static final int LOG_VALUE_RESIZE_50_50 = 0;
- private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1;
- private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2;
-
- private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0;
- private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
-
- private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
-
- /**
- * How much the background gets scaled when we are in the minimized dock state.
- */
- private static final float MINIMIZE_DOCK_SCALE = 0f;
- private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
-
- private static final Interpolator IME_ADJUST_INTERPOLATOR =
- new PathInterpolator(0.2f, 0f, 0.1f, 1f);
-
- private DividerHandleView mHandle;
- private View mBackground;
- private MinimizedDockShadow mMinimizedShadow;
- private int mStartX;
- private int mStartY;
- private int mStartPosition;
- private int mDockSide;
- private boolean mMoving;
- private int mTouchSlop;
- private boolean mBackgroundLifted;
- private boolean mIsInMinimizeInteraction;
- SnapTarget mSnapTargetBeforeMinimized;
-
- private int mDividerInsets;
- private final Display mDefaultDisplay;
-
- private int mDividerSize;
- private int mTouchElevation;
- private int mLongPressEntraceAnimDuration;
-
- private final Rect mDockedRect = new Rect();
- private final Rect mDockedTaskRect = new Rect();
- private final Rect mOtherTaskRect = new Rect();
- private final Rect mOtherRect = new Rect();
- private final Rect mDockedInsetRect = new Rect();
- private final Rect mOtherInsetRect = new Rect();
- private final Rect mLastResizeRect = new Rect();
- private final Rect mTmpRect = new Rect();
- private LegacySplitScreenController mSplitScreenController;
- private WindowManagerProxy mWindowManagerProxy;
- private DividerWindowManager mWindowManager;
- private VelocityTracker mVelocityTracker;
- private FlingAnimationUtils mFlingAnimationUtils;
- private LegacySplitDisplayLayout mSplitLayout;
- private DividerImeController mImeController;
- private DividerCallbacks mCallback;
-
- private AnimationHandler mSfVsyncAnimationHandler;
- private ValueAnimator mCurrentAnimator;
- private boolean mEntranceAnimationRunning;
- private boolean mExitAnimationRunning;
- private int mExitStartPosition;
- private boolean mDockedStackMinimized;
- private boolean mHomeStackResizable;
- private boolean mAdjustedForIme;
- private DividerState mState;
-
- private LegacySplitScreenTaskListener mTiles;
- boolean mFirstLayout = true;
- int mDividerPositionX;
- int mDividerPositionY;
-
- private final Matrix mTmpMatrix = new Matrix();
- private final float[] mTmpValues = new float[9];
-
- // The view is removed or in the process of been removed from the system.
- private boolean mRemoved;
-
- // Whether the surface for this view has been hidden regardless of actual visibility. This is
- // used interact with keyguard.
- private boolean mSurfaceHidden = false;
-
- private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm();
- if (isHorizontalDivision()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
- mContext.getString(R.string.accessibility_action_divider_top_full)));
- if (snapAlgorithm.isFirstSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
- mContext.getString(R.string.accessibility_action_divider_top_70)));
- }
- if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
- // Only show the middle target if there are more than 1 split target
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_top_50)));
- }
- if (snapAlgorithm.isLastSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
- mContext.getString(R.string.accessibility_action_divider_top_30)));
- }
- info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
- mContext.getString(R.string.accessibility_action_divider_bottom_full)));
- } else {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
- mContext.getString(R.string.accessibility_action_divider_left_full)));
- if (snapAlgorithm.isFirstSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
- mContext.getString(R.string.accessibility_action_divider_left_70)));
- }
- if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
- // Only show the middle target if there are more than 1 split target
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_left_50)));
- }
- if (snapAlgorithm.isLastSplitTargetAvailable()) {
- info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
- mContext.getString(R.string.accessibility_action_divider_left_30)));
- }
- info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
- mContext.getString(R.string.accessibility_action_divider_right_full)));
- }
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- int currentPosition = getCurrentPosition();
- SnapTarget nextTarget = null;
- DividerSnapAlgorithm snapAlgorithm = mSplitLayout.getSnapAlgorithm();
- if (action == R.id.action_move_tl_full) {
- nextTarget = snapAlgorithm.getDismissEndTarget();
- } else if (action == R.id.action_move_tl_70) {
- nextTarget = snapAlgorithm.getLastSplitTarget();
- } else if (action == R.id.action_move_tl_50) {
- nextTarget = snapAlgorithm.getMiddleTarget();
- } else if (action == R.id.action_move_tl_30) {
- nextTarget = snapAlgorithm.getFirstSplitTarget();
- } else if (action == R.id.action_move_rb_full) {
- nextTarget = snapAlgorithm.getDismissStartTarget();
- }
- if (nextTarget != null) {
- startDragging(true /* animate */, false /* touching */);
- stopDragging(currentPosition, nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
- return true;
- }
- return super.performAccessibilityAction(host, action, args);
- }
- };
-
- private final Runnable mResetBackgroundRunnable = new Runnable() {
- @Override
- public void run() {
- resetBackground();
- }
- };
-
- public DividerView(Context context) {
- this(context, null);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- final DisplayManager displayManager =
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
- mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- }
-
- public void setAnimationHandler(AnimationHandler sfVsyncAnimationHandler) {
- mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mHandle = findViewById(R.id.docked_divider_handle);
- mBackground = findViewById(R.id.docked_divider_background);
- mMinimizedShadow = findViewById(R.id.minimized_dock_shadow);
- mHandle.setOnTouchListener(this);
- final int dividerWindowWidth = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- mDividerInsets = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_insets);
- mDividerSize = dividerWindowWidth - 2 * mDividerInsets;
- mTouchElevation = getResources().getDimensionPixelSize(
- R.dimen.docked_stack_divider_lift_elevation);
- mLongPressEntraceAnimDuration = getResources().getInteger(
- R.integer.long_press_dock_anim_duration);
- mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
- boolean landscape = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_LANDSCAPE;
- mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
- landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW));
- getViewTreeObserver().addOnComputeInternalInsetsListener(this);
- mHandle.setAccessibilityDelegate(mHandleDelegate);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // Save the current target if not minimized once attached to window
- if (mDockSide != WindowManager.DOCKED_INVALID && !mIsInMinimizeInteraction) {
- saveSnapTargetBeforeMinimized(mSnapTargetBeforeMinimized);
- }
- mFirstLayout = true;
- }
-
- void onDividerRemoved() {
- mRemoved = true;
- mCallback = null;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mFirstLayout) {
- // Wait for first layout so that the ViewRootImpl surface has been created.
- initializeSurfaceState();
- mFirstLayout = false;
- }
- int minimizeLeft = 0;
- int minimizeTop = 0;
- if (mDockSide == WindowManager.DOCKED_TOP) {
- minimizeTop = mBackground.getTop();
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- minimizeLeft = mBackground.getLeft();
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
- }
- mMinimizedShadow.layout(minimizeLeft, minimizeTop,
- minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
- minimizeTop + mMinimizedShadow.getMeasuredHeight());
- if (changed) {
- notifySplitScreenBoundsChanged();
- }
- }
-
- void injectDependencies(LegacySplitScreenController splitScreenController,
- DividerWindowManager windowManager, DividerState dividerState,
- DividerCallbacks callback, LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout sdl, DividerImeController imeController,
- WindowManagerProxy wmProxy) {
- mSplitScreenController = splitScreenController;
- mWindowManager = windowManager;
- mState = dividerState;
- mCallback = callback;
- mTiles = tiles;
- mSplitLayout = sdl;
- mImeController = imeController;
- mWindowManagerProxy = wmProxy;
-
- if (mState.mRatioPositionBeforeMinimized == 0) {
- // Set the middle target as the initial state
- mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
- } else {
- repositionSnapTargetBeforeMinimized();
- }
- }
-
- /** Gets non-minimized secondary bounds of split screen. */
- public Rect getNonMinimizedSplitScreenSecondaryBounds() {
- mOtherTaskRect.set(mSplitLayout.mSecondary);
- return mOtherTaskRect;
- }
-
- private boolean inSplitMode() {
- return getVisibility() == VISIBLE;
- }
-
- /** Unlike setVisible, this directly hides the surface without changing view visibility. */
- void setHidden(boolean hidden) {
- if (mSurfaceHidden == hidden) {
- return;
- }
- mSurfaceHidden = hidden;
- post(() -> {
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- if (hidden) {
- t.hide(sc);
- } else {
- t.show(sc);
- }
- mImeController.setDimsHidden(t, hidden);
- t.apply();
- mTiles.releaseTransaction(t);
- });
- }
-
- boolean isHidden() {
- return getVisibility() != View.VISIBLE || mSurfaceHidden;
- }
-
- /** Starts dragging the divider bar. */
- public boolean startDragging(boolean animate, boolean touching) {
- cancelFlingAnimation();
- if (touching) {
- mHandle.setTouching(true, animate);
- }
- mDockSide = mSplitLayout.getPrimarySplitSide();
-
- mWindowManagerProxy.setResizing(true);
- if (touching) {
- mWindowManager.setSlippery(false);
- liftBackground();
- }
- if (mCallback != null) {
- mCallback.onDraggingStart();
- }
- return inSplitMode();
- }
-
- /** Stops dragging the divider bar. */
- public void stopDragging(int position, float velocity, boolean avoidDismissStart,
- boolean logMetrics) {
- mHandle.setTouching(false, true /* animate */);
- fling(position, velocity, avoidDismissStart, logMetrics);
- mWindowManager.setSlippery(true);
- releaseBackground();
- }
-
- private void stopDragging(int position, SnapTarget target, long duration,
- Interpolator interpolator) {
- stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
- }
-
- private void stopDragging(int position, SnapTarget target, long duration,
- Interpolator interpolator, long endDelay) {
- stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
- }
-
- private void stopDragging(int position, SnapTarget target, long duration, long startDelay,
- long endDelay, Interpolator interpolator) {
- mHandle.setTouching(false, true /* animate */);
- flingTo(position, target, duration, startDelay, endDelay, interpolator);
- mWindowManager.setSlippery(true);
- releaseBackground();
- }
-
- private void stopDragging() {
- mHandle.setTouching(false, true /* animate */);
- mWindowManager.setSlippery(true);
- mWindowManagerProxy.setResizing(false);
- releaseBackground();
- }
-
- private void updateDockSide() {
- mDockSide = mSplitLayout.getPrimarySplitSide();
- mMinimizedShadow.setDockSide(mDockSide);
- }
-
- public DividerSnapAlgorithm getSnapAlgorithm() {
- return mDockedStackMinimized ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- : mSplitLayout.getSnapAlgorithm();
- }
-
- public int getCurrentPosition() {
- return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX;
- }
-
- public boolean isMinimized() {
- return mDockedStackMinimized;
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- convertToScreenCoordinates(event);
- final int action = event.getAction() & MotionEvent.ACTION_MASK;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(event);
- mStartX = (int) event.getX();
- mStartY = (int) event.getY();
- boolean result = startDragging(true /* animate */, true /* touching */);
- if (!result) {
-
- // Weren't able to start dragging successfully, so cancel it again.
- stopDragging();
- }
- mStartPosition = getCurrentPosition();
- mMoving = false;
- return result;
- case MotionEvent.ACTION_MOVE:
- mVelocityTracker.addMovement(event);
- int x = (int) event.getX();
- int y = (int) event.getY();
- boolean exceededTouchSlop =
- isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
- || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
- if (!mMoving && exceededTouchSlop) {
- mStartX = x;
- mStartY = y;
- mMoving = true;
- }
- if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
- SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
- mStartPosition, 0 /* velocity */, false /* hardDismiss */);
- resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
- null /* transaction */);
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (!mMoving) {
- stopDragging();
- break;
- }
-
- x = (int) event.getRawX();
- y = (int) event.getRawY();
- mVelocityTracker.addMovement(event);
- mVelocityTracker.computeCurrentVelocity(1000);
- int position = calculatePosition(x, y);
- stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
- : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
- true /* log */);
- mMoving = false;
- break;
- }
- return true;
- }
-
- private void logResizeEvent(SnapTarget snapTarget) {
- if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) {
- MetricsLogger.action(
- mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
- ? LOG_VALUE_UNDOCK_MAX_OTHER
- : LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) {
- MetricsLogger.action(
- mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
- ? LOG_VALUE_UNDOCK_MAX_OTHER
- : LOG_VALUE_UNDOCK_MAX_DOCKED);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- LOG_VALUE_RESIZE_50_50);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- dockSideTopLeft(mDockSide)
- ? LOG_VALUE_RESIZE_DOCKED_SMALLER
- : LOG_VALUE_RESIZE_DOCKED_LARGER);
- } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
- dockSideTopLeft(mDockSide)
- ? LOG_VALUE_RESIZE_DOCKED_LARGER
- : LOG_VALUE_RESIZE_DOCKED_SMALLER);
- }
- }
-
- private void convertToScreenCoordinates(MotionEvent event) {
- event.setLocation(event.getRawX(), event.getRawY());
- }
-
- private void fling(int position, float velocity, boolean avoidDismissStart,
- boolean logMetrics) {
- DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
- SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
- if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
- snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
- }
- if (logMetrics) {
- logResizeEvent(snapTarget);
- }
- ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
- mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
- anim.start();
- }
-
- private void flingTo(int position, SnapTarget target, long duration, long startDelay,
- long endDelay, Interpolator interpolator) {
- ValueAnimator anim = getFlingAnimator(position, target, endDelay);
- anim.setDuration(duration);
- anim.setStartDelay(startDelay);
- anim.setInterpolator(interpolator);
- anim.start();
- }
-
- private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
- final long endDelay) {
- if (mCurrentAnimator != null) {
- cancelFlingAnimation();
- updateDockSide();
- }
- if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position);
- final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
- ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
- anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(),
- taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
- ? TASK_POSITION_SAME
- : snapTarget.taskPosition,
- snapTarget, null /* transaction */));
- Consumer<Boolean> endAction = cancelled -> {
- if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
- final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
- // Reset minimized divider position after unminimized state animation finishes.
- if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) {
- mIsInMinimizeInteraction = false;
- }
- boolean dismissed = commitSnapFlags(snapTarget);
- mWindowManagerProxy.setResizing(false);
- updateDockSide();
- mCurrentAnimator = null;
- mEntranceAnimationRunning = false;
- mExitAnimationRunning = false;
- if (!dismissed && !wasMinimizeInteraction) {
- mWindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout);
- }
- if (mCallback != null) {
- mCallback.onDraggingEnd();
- }
-
- // Record last snap target the divider moved to
- if (!mIsInMinimizeInteraction) {
- // The last snapTarget position can be negative when the last divider position was
- // offscreen. In that case, save the middle (default) SnapTarget so calculating next
- // position isn't negative.
- final SnapTarget saveTarget;
- if (snapTarget.position < 0) {
- saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
- } else {
- saveTarget = snapTarget;
- }
- final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm();
- if (saveTarget.position != snapAlgo.getDismissEndTarget().position
- && saveTarget.position != snapAlgo.getDismissStartTarget().position) {
- saveSnapTargetBeforeMinimized(saveTarget);
- }
- }
- notifySplitScreenBoundsChanged();
- };
- anim.addListener(new AnimatorListenerAdapter() {
-
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- long delay = 0;
- if (endDelay != 0) {
- delay = endDelay;
- } else if (mCancelled) {
- delay = 0;
- }
- if (delay == 0) {
- endAction.accept(mCancelled);
- } else {
- final Boolean cancelled = mCancelled;
- if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
- getHandler().postDelayed(() -> endAction.accept(cancelled), delay);
- }
- }
- });
- mCurrentAnimator = anim;
- mCurrentAnimator.setAnimationHandler(mSfVsyncAnimationHandler);
- return anim;
- }
-
- private void notifySplitScreenBoundsChanged() {
- if (mSplitLayout.mPrimary == null || mSplitLayout.mSecondary == null) {
- return;
- }
- mOtherTaskRect.set(mSplitLayout.mSecondary);
-
- mTmpRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom());
- if (isHorizontalDivision()) {
- mTmpRect.offsetTo(mHandle.getLeft(), mDividerPositionY);
- } else {
- mTmpRect.offsetTo(mDividerPositionX, mHandle.getTop());
- }
- mWindowManagerProxy.setTouchRegion(mTmpRect);
-
- mTmpRect.set(mSplitLayout.mDisplayLayout.stableInsets());
- switch (mSplitLayout.getPrimarySplitSide()) {
- case WindowManager.DOCKED_LEFT:
- mTmpRect.left = 0;
- break;
- case WindowManager.DOCKED_RIGHT:
- mTmpRect.right = 0;
- break;
- case WindowManager.DOCKED_TOP:
- mTmpRect.top = 0;
- break;
- }
- mSplitScreenController.notifyBoundsChanged(mOtherTaskRect, mTmpRect);
- }
-
- private void cancelFlingAnimation() {
- if (mCurrentAnimator != null) {
- mCurrentAnimator.cancel();
- }
- }
-
- private boolean commitSnapFlags(SnapTarget target) {
- if (target.flag == SnapTarget.FLAG_NONE) {
- return false;
- }
- final boolean dismissOrMaximize;
- if (target.flag == SnapTarget.FLAG_DISMISS_START) {
- dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
- || mDockSide == WindowManager.DOCKED_TOP;
- } else {
- dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
- || mDockSide == WindowManager.DOCKED_BOTTOM;
- }
- mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
- Transaction t = mTiles.getTransaction();
- setResizeDimLayer(t, true /* primary */, 0f);
- setResizeDimLayer(t, false /* primary */, 0f);
- t.apply();
- mTiles.releaseTransaction(t);
- return true;
- }
-
- private void liftBackground() {
- if (mBackgroundLifted) {
- return;
- }
- if (isHorizontalDivision()) {
- mBackground.animate().scaleY(1.4f);
- } else {
- mBackground.animate().scaleX(1.4f);
- }
- mBackground.animate()
- .setInterpolator(Interpolators.TOUCH_RESPONSE)
- .setDuration(TOUCH_ANIMATION_DURATION)
- .translationZ(mTouchElevation)
- .start();
-
- // Lift handle as well so it doesn't get behind the background, even though it doesn't
- // cast shadow.
- mHandle.animate()
- .setInterpolator(Interpolators.TOUCH_RESPONSE)
- .setDuration(TOUCH_ANIMATION_DURATION)
- .translationZ(mTouchElevation)
- .start();
- mBackgroundLifted = true;
- }
-
- private void releaseBackground() {
- if (!mBackgroundLifted) {
- return;
- }
- mBackground.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
- .translationZ(0)
- .scaleX(1f)
- .scaleY(1f)
- .start();
- mHandle.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
- .translationZ(0)
- .start();
- mBackgroundLifted = false;
- }
-
- private void initializeSurfaceState() {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- // Recalculate the split-layout's internal tile bounds
- mSplitLayout.resizeSplits(midPos);
- Transaction t = mTiles.getTransaction();
- if (mDockedStackMinimized) {
- int position = mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget().position;
- calculateBoundsForPosition(position, mDockSide, mDockedRect);
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
- mDividerPositionX = mDividerPositionY = position;
- resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary,
- mOtherRect, mSplitLayout.mSecondary);
- } else {
- resizeSplitSurfaces(t, mSplitLayout.mPrimary, null,
- mSplitLayout.mSecondary, null);
- }
- setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
- setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
- t.apply();
- mTiles.releaseTransaction(t);
-
- // Get the actually-visible bar dimensions (relative to full window). This is a thin
- // bar going through the center.
- final Rect dividerBar = isHorizontalDivision()
- ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(),
- mDividerInsets + mDividerSize)
- : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize,
- mSplitLayout.mDisplayLayout.height());
- final Region touchRegion = new Region(dividerBar);
- // Add in the "draggable" portion. While not visible, this is an expanded area that the
- // user can interact with.
- touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(),
- mHandle.getRight(), mHandle.getBottom()));
- mWindowManager.setTouchRegion(touchRegion);
- }
-
- void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
- Transaction t) {
- mHomeStackResizable = isHomeStackResizable;
- updateDockSide();
- if (!minimized) {
- resetBackground();
- }
- mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
- if (mDockedStackMinimized != minimized) {
- mDockedStackMinimized = minimized;
- if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) {
- // Splitscreen to minimize is about to starts after rotating landscape to seascape,
- // update display info and snap algorithm targets
- repositionSnapTargetBeforeMinimized();
- }
- if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
- cancelFlingAnimation();
- if (minimized) {
- // Relayout to recalculate the divider shadow when minimizing
- requestLayout();
- mIsInMinimizeInteraction = true;
- resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget(), t);
- } else {
- resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
- mIsInMinimizeInteraction = false;
- }
- }
- }
- }
-
- void enterSplitMode(boolean isHomeStackResizable) {
- setHidden(false);
-
- SnapTarget miniMid =
- mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget();
- if (mDockedStackMinimized) {
- mDividerPositionY = mDividerPositionX = miniMid.position;
- }
- }
-
- /**
- * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason
- * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has
- * assigned to it.
- */
- private SurfaceControl getWindowSurfaceControl() {
- return mWindowManager.mSystemWindows.getViewSurface(this);
- }
-
- void exitSplitMode() {
- // The view is going to be removed right after this function involved, updates the surface
- // in the current thread instead of posting it to the view's UI thread.
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- t.hide(sc);
- mImeController.setDimsHidden(t, true);
- t.apply();
- mTiles.releaseTransaction(t);
-
- // Reset tile bounds
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
- }
-
- void setMinimizedDockStack(boolean minimized, long animDuration,
- boolean isHomeStackResizable) {
- if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
- mHomeStackResizable = isHomeStackResizable;
- updateDockSide();
- if (mDockedStackMinimized != minimized) {
- mIsInMinimizeInteraction = true;
- mDockedStackMinimized = minimized;
- stopDragging(minimized
- ? mSnapTargetBeforeMinimized.position
- : getCurrentPosition(),
- minimized
- ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
- .getMiddleTarget()
- : mSnapTargetBeforeMinimized,
- animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
- setAdjustedForIme(false, animDuration);
- }
- if (!minimized) {
- mBackground.animate().withEndAction(mResetBackgroundRunnable);
- }
- mBackground.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(animDuration)
- .start();
- }
-
- // Needed to end any currently playing animations when they might compete with other anims
- // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe
- // these can be unified, but not today.
- void finishAnimations() {
- if (mCurrentAnimator != null) {
- mCurrentAnimator.end();
- }
- }
-
- void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- updateDockSide();
- mHandle.animate()
- .setInterpolator(IME_ADJUST_INTERPOLATOR)
- .setDuration(animDuration)
- .alpha(adjustedForIme ? 0f : 1f)
- .start();
- if (mDockSide == WindowManager.DOCKED_TOP) {
- mBackground.setPivotY(0);
- mBackground.animate()
- .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
- }
- if (!adjustedForIme) {
- mBackground.animate().withEndAction(mResetBackgroundRunnable);
- }
- mBackground.animate()
- .setInterpolator(IME_ADJUST_INTERPOLATOR)
- .setDuration(animDuration)
- .start();
- mAdjustedForIme = adjustedForIme;
- }
-
- private void saveSnapTargetBeforeMinimized(SnapTarget target) {
- mSnapTargetBeforeMinimized = target;
- mState.mRatioPositionBeforeMinimized = (float) target.position
- / (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
- : mSplitLayout.mDisplayLayout.width());
- }
-
- private void resetBackground() {
- mBackground.setPivotX(mBackground.getWidth() / 2);
- mBackground.setPivotY(mBackground.getHeight() / 2);
- mBackground.setScaleX(1f);
- mBackground.setScaleY(1f);
- mMinimizedShadow.setAlpha(0f);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- }
-
- private void repositionSnapTargetBeforeMinimized() {
- int position = (int) (mState.mRatioPositionBeforeMinimized
- * (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
- : mSplitLayout.mDisplayLayout.width()));
-
- // Set the snap target before minimized but do not save until divider is attached and not
- // minimized because it does not know its minimized state yet.
- mSnapTargetBeforeMinimized =
- mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position);
- }
-
- private int calculatePosition(int touchX, int touchY) {
- return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
- }
-
- public boolean isHorizontalDivision() {
- return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
- }
-
- private int calculateXPosition(int touchX) {
- return mStartPosition + touchX - mStartX;
- }
-
- private int calculateYPosition(int touchY) {
- return mStartPosition + touchY - mStartY;
- }
-
- private void alignTopLeft(Rect containingRect, Rect rect) {
- int width = rect.width();
- int height = rect.height();
- rect.set(containingRect.left, containingRect.top,
- containingRect.left + width, containingRect.top + height);
- }
-
- private void alignBottomRight(Rect containingRect, Rect rect) {
- int width = rect.width();
- int height = rect.height();
- rect.set(containingRect.right - width, containingRect.bottom - height,
- containingRect.right, containingRect.bottom);
- }
-
- private void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
- mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
- mDividerSize);
- }
-
- private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
- resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
- }
-
- void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
- resizeSplitSurfaces(t, dockedRect, null, otherRect, null);
- }
-
- private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect,
- Rect otherRect, Rect otherTaskRect) {
- dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect;
- otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect;
-
- mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT
- ? otherRect.right : dockedRect.right;
- mDividerPositionY = dockedRect.bottom;
-
- if (DEBUG) {
- Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect
- + " " + otherRect + " " + otherTaskRect);
- }
-
- t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
- Rect crop = new Rect(dockedRect);
- crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
- -Math.min(dockedTaskRect.top - dockedRect.top, 0));
- t.setWindowCrop(mTiles.mPrimarySurface, crop);
- t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top);
- crop.set(otherRect);
- crop.offsetTo(-(otherTaskRect.left - otherRect.left),
- -(otherTaskRect.top - otherRect.top));
- t.setWindowCrop(mTiles.mSecondarySurface, crop);
- final SurfaceControl dividerCtrl = getWindowSurfaceControl();
- if (dividerCtrl != null) {
- if (isHorizontalDivision()) {
- t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets);
- } else {
- t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
- }
- }
- }
-
- void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
- SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
- if (alpha <= 0.001f) {
- t.hide(dim);
- } else {
- t.setAlpha(dim, alpha);
- t.show(dim);
- }
- }
-
- void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
- Transaction transaction) {
- if (mRemoved) {
- // This divider view has been removed so shouldn't have any additional influence.
- return;
- }
- calculateBoundsForPosition(position, mDockSide, mDockedRect);
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
-
- if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
- return;
- }
-
- // Make sure shadows are updated
- if (mBackground.getZ() > 0f) {
- mBackground.invalidate();
- }
-
- final boolean ownTransaction = transaction == null;
- final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
- mLastResizeRect.set(mDockedRect);
- if (mIsInMinimizeInteraction) {
- calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
- mDockedTaskRect);
- calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
- DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
-
- // Move a right-docked-app to line up with the divider while dragging it
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(Math.max(position, -mDividerSize)
- - mDockedTaskRect.left + mDividerSize, 0);
- }
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- if (ownTransaction) {
- t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
- t.apply();
- mTiles.releaseTransaction(t);
- }
- return;
- }
-
- if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
-
- // Move a docked app if from the right in position with the divider up to insets
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(Math.max(position, -mDividerSize)
- - mDockedTaskRect.left + mDividerSize, 0);
- }
- calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherTaskRect);
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
- mDockedInsetRect.set(mDockedTaskRect);
- calculateBoundsForPosition(mExitStartPosition,
- DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
- mOtherInsetRect.set(mOtherTaskRect);
- applyExitAnimationParallax(mOtherTaskRect, position);
-
- // Move a right-docked-app to line up with the divider while dragging it
- if (mDockSide == DOCKED_RIGHT) {
- mDockedTaskRect.offset(position + mDividerSize, 0);
- }
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else if (taskPosition != TASK_POSITION_SAME) {
- calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
- mOtherRect);
- int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
- int taskPositionDocked =
- restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
- int taskPositionOther =
- restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
- calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
- calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
- mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(),
- mSplitLayout.mDisplayLayout.height());
- alignTopLeft(mDockedRect, mDockedTaskRect);
- alignTopLeft(mOtherRect, mOtherTaskRect);
- mDockedInsetRect.set(mDockedTaskRect);
- mOtherInsetRect.set(mOtherTaskRect);
- if (dockSideTopLeft(mDockSide)) {
- alignTopLeft(mTmpRect, mDockedInsetRect);
- alignBottomRight(mTmpRect, mOtherInsetRect);
- } else {
- alignBottomRight(mTmpRect, mDockedInsetRect);
- alignTopLeft(mTmpRect, mOtherInsetRect);
- }
- applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
- taskPositionDocked);
- applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
- taskPositionOther);
- resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
- } else {
- resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null);
- }
- SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
- float dimFraction = getDimFraction(position, closestDismissTarget);
- setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
- if (ownTransaction) {
- t.apply();
- mTiles.releaseTransaction(t);
- }
- }
-
- private void applyExitAnimationParallax(Rect taskRect, int position) {
- if (mDockSide == WindowManager.DOCKED_TOP) {
- taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
- }
- }
-
- private float getDimFraction(int position, SnapTarget dismissTarget) {
- if (mEntranceAnimationRunning) {
- return 0f;
- }
- float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
- fraction = Math.max(0, Math.min(fraction, 1f));
- fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
- return fraction;
- }
-
- /**
- * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
- * 0 size.
- */
- private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
- SnapTarget snapTarget) {
- if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
- return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position,
- mStartPosition);
- } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
- && dockSideBottomRight(dockSide)) {
- return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position,
- mStartPosition);
- } else {
- return taskPosition;
- }
- }
-
- /**
- * Applies a parallax to the task when dismissing.
- */
- private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
- int position, int taskPosition) {
- float fraction = Math.min(1, Math.max(0,
- mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position)));
- SnapTarget dismissTarget = null;
- SnapTarget splitTarget = null;
- int start = 0;
- if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
- && dockSideTopLeft(dockSide)) {
- dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
- splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget();
- start = taskPosition;
- } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
- && dockSideBottomRight(dockSide)) {
- dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget();
- splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget();
- start = splitTarget.position;
- }
- if (dismissTarget != null && fraction > 0f
- && isDismissing(splitTarget, position, dockSide)) {
- fraction = calculateParallaxDismissingFraction(fraction, dockSide);
- int offsetPosition = (int) (start + fraction
- * (dismissTarget.position - splitTarget.position));
- int width = taskRect.width();
- int height = taskRect.height();
- switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
- taskRect.left = offsetPosition - width;
- taskRect.right = offsetPosition;
- break;
- case WindowManager.DOCKED_RIGHT:
- taskRect.left = offsetPosition + mDividerSize;
- taskRect.right = offsetPosition + width + mDividerSize;
- break;
- case WindowManager.DOCKED_TOP:
- taskRect.top = offsetPosition - height;
- taskRect.bottom = offsetPosition;
- break;
- case WindowManager.DOCKED_BOTTOM:
- taskRect.top = offsetPosition + mDividerSize;
- taskRect.bottom = offsetPosition + height + mDividerSize;
- break;
- }
- }
- }
-
- /**
- * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
- * slowing down parallax effect
- */
- private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
- float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
-
- // Less parallax at the top, just because.
- if (dockSide == WindowManager.DOCKED_TOP) {
- result /= 2f;
- }
- return result;
- }
-
- private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
- if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
- return position < snapTarget.position;
- } else {
- return position > snapTarget.position;
- }
- }
-
- private boolean isDismissTargetPrimary(SnapTarget dismissTarget) {
- return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
- || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
- && dockSideBottomRight(mDockSide));
- }
-
- /**
- * @return true if and only if {@code dockSide} is top or left
- */
- private static boolean dockSideTopLeft(int dockSide) {
- return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
- }
-
- /**
- * @return true if and only if {@code dockSide} is bottom or right
- */
- private static boolean dockSideBottomRight(int dockSide) {
- return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
- }
-
- @Override
- public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
- mHandle.getBottom());
- inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
- mBackground.getRight(), mBackground.getBottom(), Op.UNION);
- }
-
- void onUndockingTask() {
- int dockSide = mSplitLayout.getPrimarySplitSide();
- if (inSplitMode()) {
- startDragging(false /* animate */, false /* touching */);
- SnapTarget target = dockSideTopLeft(dockSide)
- ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget()
- : mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
-
- // Don't start immediately - give a little bit time to settle the drag resize change.
- mExitAnimationRunning = true;
- mExitStartPosition = getCurrentPosition();
- stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
- 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
- }
- }
-
- private int calculatePositionForInsetBounds() {
- mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect);
- return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java
deleted file mode 100644
index 2c3ae68e4749..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 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.legacysplitscreen;
-
-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_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
-
-import android.graphics.PixelFormat;
-import android.graphics.Region;
-import android.os.Binder;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.wm.shell.common.SystemWindows;
-
-/**
- * Manages the window parameters of the docked stack divider.
- */
-final class DividerWindowManager {
-
- private static final String WINDOW_TITLE = "DockedStackDivider";
-
- final SystemWindows mSystemWindows;
- private WindowManager.LayoutParams mLp;
- private View mView;
-
- DividerWindowManager(SystemWindows systemWindows) {
- mSystemWindows = systemWindows;
- }
-
- /** Add a divider view */
- void add(View view, int width, int height, int displayId) {
- mLp = new WindowManager.LayoutParams(
- width, height, TYPE_DOCK_DIVIDER,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
- | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
- PixelFormat.TRANSLUCENT);
- mLp.token = new Binder();
- mLp.setTitle(WINDOW_TITLE);
- mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mSystemWindows.addView(view, mLp, displayId, SHELL_ROOT_LAYER_DIVIDER);
- mView = view;
- }
-
- void remove() {
- if (mView != null) {
- mSystemWindows.removeView(mView);
- }
- mView = null;
- }
-
- void setSlippery(boolean slippery) {
- boolean changed = false;
- if (slippery && (mLp.flags & FLAG_SLIPPERY) == 0) {
- mLp.flags |= FLAG_SLIPPERY;
- changed = true;
- } else if (!slippery && (mLp.flags & FLAG_SLIPPERY) != 0) {
- mLp.flags &= ~FLAG_SLIPPERY;
- changed = true;
- }
- if (changed) {
- mSystemWindows.updateViewLayout(mView, mLp);
- }
- }
-
- void setTouchable(boolean touchable) {
- if (mView == null) {
- return;
- }
- boolean changed = false;
- if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
- mLp.flags |= FLAG_NOT_TOUCHABLE;
- changed = true;
- } else if (touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) != 0) {
- mLp.flags &= ~FLAG_NOT_TOUCHABLE;
- changed = true;
- }
- if (changed) {
- mSystemWindows.updateViewLayout(mView, mLp);
- }
- }
-
- /** Sets the touch region to `touchRegion`. Use null to unset.*/
- void setTouchRegion(Region touchRegion) {
- if (mView == null) {
- return;
- }
- mSystemWindows.setTouchableRegion(mView, touchRegion);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java
deleted file mode 100644
index 4fe28e630114..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 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.legacysplitscreen;
-
-import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
-import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.widget.TextView;
-
-import com.android.wm.shell.R;
-
-/**
- * Translucent activity that gets started on top of a task in multi-window to inform the user that
- * we forced the activity below to be resizable.
- *
- * Note: This activity runs on the main thread of the process hosting the Shell lib.
- */
-public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
-
- public static final String EXTRA_FORCED_RESIZEABLE_REASON = "extra_forced_resizeable_reason";
-
- private static final long DISMISS_DELAY = 2500;
-
- private final Runnable mFinishRunnable = new Runnable() {
- @Override
- public void run() {
- finish();
- }
- };
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.forced_resizable_activity);
- TextView tv = findViewById(com.android.internal.R.id.message);
- int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1);
- String text;
- switch (reason) {
- case FORCED_RESIZEABLE_REASON_SPLIT_SCREEN:
- text = getString(R.string.dock_forced_resizable);
- break;
- case FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY:
- text = getString(R.string.forced_resizable_secondary_display);
- break;
- default:
- throw new IllegalArgumentException("Unexpected forced resizeable reason: "
- + reason);
- }
- tv.setText(text);
- getWindow().setTitle(text);
- getWindow().getDecorView().setOnTouchListener(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- finish();
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- finish();
- return true;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- finish();
- return true;
- }
-
- @Override
- public void finish() {
- super.finish();
- overridePendingTransition(0, R.anim.forced_resizable_exit);
- }
-
- @Override
- public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- // Do nothing
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java
deleted file mode 100644
index 139544f951ce..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2016 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.legacysplitscreen;
-
-
-import static com.android.wm.shell.legacysplitscreen.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON;
-
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.widget.Toast;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.ShellExecutor;
-
-import java.util.function.Consumer;
-
-/**
- * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
- */
-final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks {
-
- private static final String SELF_PACKAGE_NAME = "com.android.systemui";
-
- private static final int TIMEOUT = 1000;
- private final Context mContext;
- private final ShellExecutor mMainExecutor;
- private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
- private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
- private boolean mDividerDragging;
-
- private final Runnable mTimeoutRunnable = this::showPending;
-
- private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
- if (!exists) {
- mPackagesShownInSession.clear();
- }
- };
-
- /** Record of force resized task that's pending to be handled. */
- private class PendingTaskRecord {
- int mTaskId;
- /**
- * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
- * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}
- */
- int mReason;
-
- PendingTaskRecord(int taskId, int reason) {
- this.mTaskId = taskId;
- this.mReason = reason;
- }
- }
-
- ForcedResizableInfoActivityController(Context context,
- LegacySplitScreenController splitScreenController,
- ShellExecutor mainExecutor) {
- mContext = context;
- mMainExecutor = mainExecutor;
- splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
- }
-
- @Override
- public void onDraggingStart() {
- mDividerDragging = true;
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- }
-
- @Override
- public void onDraggingEnd() {
- mDividerDragging = false;
- showPending();
- }
-
- void onAppTransitionFinished() {
- if (!mDividerDragging) {
- showPending();
- }
- }
-
- void activityForcedResizable(String packageName, int taskId, int reason) {
- if (debounce(packageName)) {
- return;
- }
- mPendingTasks.add(new PendingTaskRecord(taskId, reason));
- postTimeout();
- }
-
- void activityDismissingSplitScreen() {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- }
-
- void activityLaunchOnSecondaryDisplayFailed() {
- Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
- Toast.LENGTH_SHORT).show();
- }
-
- private void showPending() {
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- for (int i = mPendingTasks.size() - 1; i >= 0; i--) {
- PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
- Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(pendingRecord.mTaskId);
- // Set as task overlay and allow to resume, so that when an app enters split-screen and
- // becomes paused, the overlay will still be shown.
- options.setTaskOverlay(true, true /* canResume */);
- intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.mReason);
- mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
- }
- mPendingTasks.clear();
- }
-
- private void postTimeout() {
- mMainExecutor.removeCallbacks(mTimeoutRunnable);
- mMainExecutor.executeDelayed(mTimeoutRunnable, TIMEOUT);
- }
-
- private boolean debounce(String packageName) {
- if (packageName == null) {
- return false;
- }
-
- // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that
- // triggers another notification. So ignore our own activity.
- if (SELF_PACKAGE_NAME.equals(packageName)) {
- return true;
- }
- boolean debounce = mPackagesShownInSession.contains(packageName);
- mPackagesShownInSession.add(packageName);
- return debounce;
- }
-}
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
deleted file mode 100644
index f201634d3d4a..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ /dev/null
@@ -1,326 +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.legacysplitscreen;
-
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.util.RotationUtils.rotateBounds;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.TypedValue;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.wm.shell.common.DisplayLayout;
-
-/**
- * Handles split-screen related internal display layout. In general, this represents the
- * WM-facing understanding of the splits.
- */
-public class LegacySplitDisplayLayout {
- /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
- * restrict IME adjustment so that a min portion of top stack remains visible.*/
- private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
-
- private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
-
- LegacySplitScreenTaskListener mTiles;
- DisplayLayout mDisplayLayout;
- Context mContext;
-
- // Lazy stuff
- boolean mResourcesValid = false;
- int mDividerSize;
- int mDividerSizeInactive;
- private DividerSnapAlgorithm mSnapAlgorithm = null;
- private DividerSnapAlgorithm mMinimizedSnapAlgorithm = null;
- Rect mPrimary = null;
- Rect mSecondary = null;
- Rect mAdjustedPrimary = null;
- Rect mAdjustedSecondary = null;
- final Rect mTmpBounds = new Rect();
-
- public LegacySplitDisplayLayout(Context ctx, DisplayLayout dl,
- LegacySplitScreenTaskListener taskTiles) {
- mTiles = taskTiles;
- mDisplayLayout = dl;
- mContext = ctx;
- }
-
- void rotateTo(int newRotation) {
- mDisplayLayout.rotateTo(mContext.getResources(), newRotation);
- final Configuration config = new Configuration();
- config.unset();
- config.orientation = mDisplayLayout.getOrientation();
- Rect tmpRect = new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
- tmpRect.inset(mDisplayLayout.nonDecorInsets());
- config.windowConfiguration.setAppBounds(tmpRect);
- tmpRect.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
- tmpRect.inset(mDisplayLayout.stableInsets());
- config.screenWidthDp = (int) (tmpRect.width() / mDisplayLayout.density());
- config.screenHeightDp = (int) (tmpRect.height() / mDisplayLayout.density());
- mContext = mContext.createConfigurationContext(config);
- mSnapAlgorithm = null;
- mMinimizedSnapAlgorithm = null;
- mResourcesValid = false;
- }
-
- private void updateResources() {
- if (mResourcesValid) {
- return;
- }
- mResourcesValid = true;
- Resources res = mContext.getResources();
- mDividerSize = DockedDividerUtils.getDividerSize(res,
- DockedDividerUtils.getDividerInsets(res));
- mDividerSizeInactive = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, DIVIDER_WIDTH_INACTIVE_DP, res.getDisplayMetrics());
- }
-
- int getPrimarySplitSide() {
- switch (mDisplayLayout.getNavigationBarPosition(mContext.getResources())) {
- case DisplayLayout.NAV_BAR_BOTTOM:
- return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP;
- case DisplayLayout.NAV_BAR_LEFT:
- return DOCKED_RIGHT;
- case DisplayLayout.NAV_BAR_RIGHT:
- return DOCKED_LEFT;
- default:
- return DOCKED_INVALID;
- }
- }
-
- DividerSnapAlgorithm getSnapAlgorithm() {
- if (mSnapAlgorithm == null) {
- updateResources();
- boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
- mSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
- isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide());
- }
- return mSnapAlgorithm;
- }
-
- DividerSnapAlgorithm getMinimizedSnapAlgorithm(boolean homeStackResizable) {
- if (mMinimizedSnapAlgorithm == null) {
- updateResources();
- boolean isHorizontalDivision = !mDisplayLayout.isLandscape();
- mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(),
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize,
- isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide(),
- true /* isMinimized */, homeStackResizable);
- }
- return mMinimizedSnapAlgorithm;
- }
-
- /**
- * 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;
- 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) {
- 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));
- }
- }
-
- Rect calcResizableMinimizedHomeStackBounds() {
- DividerSnapAlgorithm.SnapTarget miniMid =
- getMinimizedSnapAlgorithm(true /* resizable */).getMiddleTarget();
- Rect homeBounds = new Rect();
- DockedDividerUtils.calculateBoundsForPosition(miniMid.position,
- DockedDividerUtils.invertDockSide(getPrimarySplitSide()), homeBounds,
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
- return homeBounds;
- }
-
- /**
- * Updates the adjustment depending on it's current state.
- */
- void updateAdjustedBounds(int currImeTop, int hiddenTop, int shownTop) {
- adjustForIME(mDisplayLayout, currImeTop, hiddenTop, shownTop, mDividerSize,
- mDividerSizeInactive, mPrimary, mSecondary);
- }
-
- /** Assumes top/bottom split. Splits are not adjusted for left/right splits. */
- private void adjustForIME(DisplayLayout dl, int currImeTop, int hiddenTop, int shownTop,
- int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
- if (mAdjustedPrimary == null) {
- mAdjustedPrimary = new Rect();
- mAdjustedSecondary = new Rect();
- }
-
- final Rect displayStableRect = new Rect();
- dl.getStableBounds(displayStableRect);
-
- final float shownFraction = ((float) (currImeTop - hiddenTop)) / (shownTop - hiddenTop);
- final int currDividerWidth =
- (int) (dividerWidthInactive * shownFraction + dividerWidth * (1.f - shownFraction));
-
- // Calculate the highest we can move the bottom of the top stack to keep 30% visible.
- final int minTopStackBottom = displayStableRect.top
- + (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN);
- // Based on that, calculate the maximum amount we'll allow the ime to shift things.
- final int maxOffset = mPrimary.bottom - minTopStackBottom;
- // Calculate how much we would shift things without limits (basically the height of ime).
- final int desiredOffset = hiddenTop - shownTop;
- // Calculate an "adjustedTop" which is the currImeTop but restricted by our constraints.
- // We want an effect where the adjustment only occurs during the "highest" portion of the
- // ime animation. This is done by shifting the adjustment values by the difference in
- // offsets (effectively playing the whole adjustment animation some fixed amount of pixels
- // below the ime top).
- final int topCorrection = Math.max(0, desiredOffset - maxOffset);
- final int adjustedTop = currImeTop + topCorrection;
- // The actual yOffset is the distance between adjustedTop and the bottom of the display.
- // Since our adjustedTop values are playing "below" the ime, we clamp at 0 so we only
- // see adjustment upward.
- final int yOffset = Math.max(0, dl.height() - adjustedTop);
-
- // TOP
- // Reduce the offset by an additional small amount to squish the divider bar.
- mAdjustedPrimary.set(primaryBounds);
- mAdjustedPrimary.offset(0, -yOffset + (dividerWidth - currDividerWidth));
-
- // BOTTOM
- mAdjustedSecondary.set(secondaryBounds);
- mAdjustedSecondary.offset(0, -yOffset);
- }
-
- static int getSmallestWidthDpForBounds(@NonNull Context context, DisplayLayout dl,
- Rect bounds) {
- int dividerSize = DockedDividerUtils.getDividerSize(context.getResources(),
- DockedDividerUtils.getDividerInsets(context.getResources()));
-
- int minWidth = Integer.MAX_VALUE;
-
- // Go through all screen orientations and find the orientation in which the task has the
- // smallest width.
- Rect tmpRect = new Rect();
- Rect rotatedDisplayRect = new Rect();
- Rect displayRect = new Rect(0, 0, dl.width(), dl.height());
-
- DisplayLayout tmpDL = new DisplayLayout();
- for (int rotation = 0; rotation < 4; rotation++) {
- tmpDL.set(dl);
- tmpDL.rotateTo(context.getResources(), rotation);
- DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize);
-
- tmpRect.set(bounds);
- rotateBounds(tmpRect, displayRect, dl.rotation(), rotation);
- rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height());
- final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect,
- tmpDL.getOrientation());
- final int position = DockedDividerUtils.calculatePositionForBounds(tmpRect, dockSide,
- dividerSize);
-
- final int snappedPosition =
- snap.calculateNonDismissingSnapTarget(position).position;
- DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, tmpRect,
- tmpDL.width(), tmpDL.height(), dividerSize);
- Rect insettedDisplay = new Rect(rotatedDisplayRect);
- insettedDisplay.inset(tmpDL.stableInsets());
- tmpRect.intersect(insettedDisplay);
- minWidth = Math.min(tmpRect.width(), minWidth);
- }
- return (int) (minWidth / dl.density());
- }
-
- static DividerSnapAlgorithm initSnapAlgorithmForRotation(Context context, DisplayLayout dl,
- int dividerSize) {
- final Configuration config = new Configuration();
- config.unset();
- config.orientation = dl.getOrientation();
- Rect tmpRect = new Rect(0, 0, dl.width(), dl.height());
- tmpRect.inset(dl.nonDecorInsets());
- config.windowConfiguration.setAppBounds(tmpRect);
- tmpRect.set(0, 0, dl.width(), dl.height());
- tmpRect.inset(dl.stableInsets());
- config.screenWidthDp = (int) (tmpRect.width() / dl.density());
- config.screenHeightDp = (int) (tmpRect.height() / dl.density());
- final Context rotationContext = context.createConfigurationContext(config);
- return new DividerSnapAlgorithm(
- rotationContext.getResources(), dl.width(), dl.height(), dividerSize,
- config.orientation == ORIENTATION_PORTRAIT, dl.stableInsets());
- }
-
- /**
- * Get the current primary-split side. Determined by its location of {@param bounds} within
- * {@param displayRect} but if both are the same, it will try to dock to each side and determine
- * if allowed in its respected {@param orientation}.
- *
- * @param bounds bounds of the primary split task to get which side is docked
- * @param displayRect bounds of the display that contains the primary split task
- * @param orientation the origination of device
- * @return current primary-split side
- */
- static int getPrimarySplitSide(Rect bounds, Rect displayRect, int orientation) {
- if (orientation == ORIENTATION_PORTRAIT) {
- // Portrait mode, docked either at the top or the bottom.
- final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
- if (diff < 0) {
- return DOCKED_BOTTOM;
- } else {
- // Top is default
- return DOCKED_TOP;
- }
- } else if (orientation == ORIENTATION_LANDSCAPE) {
- // Landscape mode, docked either on the left or on the right.
- final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
- if (diff < 0) {
- return DOCKED_RIGHT;
- }
- return DOCKED_LEFT;
- }
- return DOCKED_INVALID;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java
deleted file mode 100644
index 499a9c5fa631..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java
+++ /dev/null
@@ -1,85 +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.legacysplitscreen;
-
-import android.graphics.Rect;
-import android.window.WindowContainerToken;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-import java.io.PrintWriter;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-/**
- * Interface to engage split screen feature.
- */
-@ExternalThread
-public interface LegacySplitScreen {
- /** Called when keyguard showing state changed. */
- void onKeyguardVisibilityChanged(boolean isShowing);
-
- /** Returns {@link DividerView}. */
- DividerView getDividerView();
-
- /** Returns {@code true} if one of the split screen is in minimized mode. */
- boolean isMinimized();
-
- /** Returns {@code true} if the home stack is resizable. */
- boolean isHomeStackResizable();
-
- /** Returns {@code true} if the divider is visible. */
- boolean isDividerVisible();
-
- /** Switch to minimized state if appropriate. */
- void setMinimized(boolean minimized);
-
- /** Called when there's a task undocking. */
- void onUndockingTask();
-
- /** Called when app transition finished. */
- void onAppTransitionFinished();
-
- /** Dumps current status of Split Screen. */
- void dump(PrintWriter pw);
-
- /** Registers listener that gets called whenever the existence of the divider changes. */
- void registerInSplitScreenListener(Consumer<Boolean> listener);
-
- /** Unregisters listener that gets called whenever the existence of the divider changes. */
- void unregisterInSplitScreenListener(Consumer<Boolean> listener);
-
- /** Registers listener that gets called whenever the split screen bounds changes. */
- void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
-
- /** @return the container token for the secondary split root task. */
- WindowContainerToken getSecondaryRoot();
-
- /**
- * Splits the primary task if feasible, this is to preserve legacy way to toggle split screen.
- * Like triggering split screen through long pressing recents app button or through
- * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}.
- *
- * @return {@code true} if it successes to split the primary task.
- */
- boolean splitPrimaryTask();
-
- /**
- * Exits the split to make the primary task fullscreen.
- */
- void dismissSplitToPrimaryTask();
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
deleted file mode 100644
index 67e487de0993..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ /dev/null
@@ -1,762 +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.legacysplitscreen;
-
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.animation.AnimationHandler;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityTaskManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Toast;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.wm.shell.R;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayChangeController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TaskStackListenerCallback;
-import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-/**
- * Controls split screen feature.
- */
-public class LegacySplitScreenController implements DisplayController.OnDisplaysChangedListener {
- static final boolean DEBUG = false;
-
- private static final String TAG = "SplitScreenCtrl";
- private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
- private final Context mContext;
- private final DisplayChangeController.OnDisplayChangingListener mRotationController;
- private final DisplayController mDisplayController;
- private final DisplayImeController mImeController;
- private final DividerImeController mImePositionProcessor;
- private final DividerState mDividerState = new DividerState();
- private final ForcedResizableInfoActivityController mForcedResizableController;
- private final ShellExecutor mMainExecutor;
- private final AnimationHandler mSfVsyncAnimationHandler;
- private final LegacySplitScreenTaskListener mSplits;
- private final SystemWindows mSystemWindows;
- final TransactionPool mTransactionPool;
- private final WindowManagerProxy mWindowManagerProxy;
- private final TaskOrganizer mTaskOrganizer;
- private final SplitScreenImpl mImpl = new SplitScreenImpl();
-
- private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
- = new CopyOnWriteArrayList<>();
- private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
- new ArrayList<>();
-
-
- private DividerWindowManager mWindowManager;
- private DividerView mView;
-
- // Keeps track of real-time split geometry including snap positions and ime adjustments
- private LegacySplitDisplayLayout mSplitLayout;
-
- // Transient: this contains the layout calculated for a new rotation requested by WM. This is
- // kept around so that we can wait for a matching configuration change and then use the exact
- // layout that we sent back to WM.
- private LegacySplitDisplayLayout mRotateSplitLayout;
-
- private boolean mIsKeyguardShowing;
- private boolean mVisible = false;
- private volatile boolean mMinimized = false;
- private volatile boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
-
- public LegacySplitScreenController(Context context,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
- TaskStackListenerImpl taskStackListener, Transitions transitions,
- ShellExecutor mainExecutor, AnimationHandler sfVsyncAnimationHandler) {
- mContext = context;
- mDisplayController = displayController;
- mSystemWindows = systemWindows;
- mImeController = imeController;
- mMainExecutor = mainExecutor;
- mSfVsyncAnimationHandler = sfVsyncAnimationHandler;
- mForcedResizableController = new ForcedResizableInfoActivityController(context, this,
- mainExecutor);
- mTransactionPool = transactionPool;
- mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
- mTaskOrganizer = shellTaskOrganizer;
- mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, transitions,
- syncQueue);
- mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mMainExecutor,
- shellTaskOrganizer);
- mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
- return;
- }
- WindowContainerTransaction t = new WindowContainerTransaction();
- DisplayLayout displayLayout =
- new DisplayLayout(mDisplayController.getDisplayLayout(display));
- LegacySplitDisplayLayout sdl =
- new LegacySplitDisplayLayout(mContext, displayLayout, mSplits);
- sdl.rotateTo(toRotation);
- mRotateSplitLayout = sdl;
- // snap resets to middle target when not minimized and rotation changed.
- final int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : sdl.getSnapAlgorithm().getMiddleTarget().position;
- DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
- final DividerSnapAlgorithm.SnapTarget target =
- snap.calculateNonDismissingSnapTarget(position);
- sdl.resizeSplits(target.position, t);
-
- if (isSplitActive() && mHomeStackResizable) {
- mWindowManagerProxy
- .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
- }
- if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
- // Because sync transactions are serialized, its possible for an "older"
- // bounds-change to get applied after a screen rotation. In that case, we
- // want to actually defer on that rather than apply immediately. Of course,
- // this means that the bounds may not change until after the rotation so
- // the user might see some artifacts. This should be rare.
- Slog.w(TAG, "Screen rotated while other operations were pending, this may"
- + " result in some graphical artifacts.");
- } else {
- wct.merge(t, true /* transfer */);
- }
- };
-
- mWindowManager = new DividerWindowManager(mSystemWindows);
-
- // No need to listen to display window container or create root tasks if the device is not
- // using legacy split screen.
- if (!context.getResources().getBoolean(com.android.internal.R.bool.config_useLegacySplit)) {
- return;
- }
-
-
- mDisplayController.addDisplayWindowListener(this);
- // Don't initialize the divider or anything until we get the default display.
-
- taskStackListener.addListener(
- new TaskStackListenerCallback() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !mSplits.isSplitScreenSupported()) {
- return;
- }
-
- if (isMinimized()) {
- onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- mForcedResizableController.activityForcedResizable(packageName, taskId,
- reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- mForcedResizableController.activityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
- }
- });
- }
-
- public LegacySplitScreen asLegacySplitScreen() {
- return mImpl;
- }
-
- public void onSplitScreenSupported() {
- // Set starting tile bounds based on middle target
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mSplitLayout.resizeSplits(midPos, tct);
- mTaskOrganizer.applyTransaction(tct);
- }
-
- public void onKeyguardVisibilityChanged(boolean showing) {
- if (!isSplitActive() || mView == null) {
- return;
- }
- mView.setHidden(showing);
- mIsKeyguardShowing = showing;
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- mImeController.addPositionProcessor(mImePositionProcessor);
- mDisplayController.addDisplayChangingController(mRotationController);
- if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
- removeDivider();
- return;
- }
- try {
- mSplits.init();
- } catch (Exception e) {
- Slog.e(TAG, "Failed to register docked stack listener", e);
- removeDivider();
- return;
- }
- }
-
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
- return;
- }
- mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- if (mRotateSplitLayout == null) {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- mSplitLayout.resizeSplits(midPos, tct);
- mTaskOrganizer.applyTransaction(tct);
- } else if (mSplitLayout.mDisplayLayout.rotation()
- == mRotateSplitLayout.mDisplayLayout.rotation()) {
- mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
- mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
- mRotateSplitLayout = null;
- }
- if (isSplitActive()) {
- update(newConfig);
- }
- }
-
- public boolean isMinimized() {
- return mMinimized;
- }
-
- public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- public DividerView getDividerView() {
- return mView;
- }
-
- public boolean isDividerVisible() {
- return mView != null && mView.getVisibility() == View.VISIBLE;
- }
-
- /**
- * This indicates that at-least one of the splits has content. This differs from
- * isDividerVisible because the divider is only visible once *everything* is in split mode
- * while this only cares if some things are (eg. while entering/exiting as well).
- */
- public boolean isSplitActive() {
- return mSplits.mPrimary != null && mSplits.mSecondary != null
- && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
- || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
- }
-
- public void addDivider(Configuration configuration) {
- Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
- mView = (DividerView)
- LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
- mView.setAnimationHandler(mSfVsyncAnimationHandler);
- DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController,
- mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
- mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
- final int size = dctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
- final int width = landscape ? size : displayLayout.width();
- final int height = landscape ? displayLayout.height() : size;
- mWindowManager.add(mView, width, height, mContext.getDisplayId());
- }
-
- public void removeDivider() {
- if (mView != null) {
- mView.onDividerRemoved();
- }
- mWindowManager.remove();
- }
-
- public void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mIsKeyguardShowing;
-
- removeDivider();
- addDivider(configuration);
-
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
- }
-
- public void onTaskVanished() {
- removeDivider();
- }
-
- public void updateVisibility(final boolean visible) {
- if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
- if (mVisible != visible) {
- mVisible = visible;
- mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-
- if (visible) {
- mView.enterSplitMode(mHomeStackResizable);
- // Update state because animations won't finish.
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
-
- } else {
- mView.exitSplitMode();
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
- }
- // Notify existence listeners
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.removeIf(wf -> {
- Consumer<Boolean> l = wf.get();
- if (l != null) l.accept(visible);
- return l == null;
- });
- }
- }
- }
-
- public void setMinimized(final boolean minimized) {
- if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
- mMainExecutor.execute(() -> {
- if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
- if (!mVisible) {
- return;
- }
- setHomeMinimized(minimized);
- });
- }
-
- public void setHomeMinimized(final boolean minimized) {
- if (DEBUG) {
- Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
- + mHomeStackResizable + " split:" + isDividerVisible());
- }
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final boolean minimizedChanged = mMinimized != minimized;
- // Update minimized state
- if (minimizedChanged) {
- mMinimized = minimized;
- }
- // Always set this because we could be entering split when mMinimized is already true
- wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
-
- // Sync state to DividerView if it exists.
- if (mView != null) {
- final int displayId = mView.getDisplay() != null
- ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
- // pause ime here (before updateMinimizedDockedStack)
- if (mMinimized) {
- mImePositionProcessor.pause(displayId);
- }
- if (minimizedChanged) {
- // This conflicts with IME adjustment, so only call it when things change.
- mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
- }
- if (!mMinimized) {
- // afterwards so it can end any animations started in view
- mImePositionProcessor.resume(displayId);
- }
- }
- updateTouchable();
-
- // If we are only setting focusability, a sync transaction isn't necessary (in fact it
- // can interrupt other animations), so see if it can be submitted on pending instead.
- if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) {
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- public void setAdjustedForIme(boolean adjustedForIme) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- mAdjustedForIme = adjustedForIme;
- updateTouchable();
- }
-
- public void updateTouchable() {
- mWindowManager.setTouchable(!mAdjustedForIme);
- }
-
- public void onUndockingTask() {
- if (mView != null) {
- mView.onUndockingTask();
- }
- }
-
- public void onAppTransitionFinished() {
- if (mView == null) {
- return;
- }
- mForcedResizableController.onAppTransitionFinished();
- }
-
- public void dump(PrintWriter pw) {
- pw.print(" mVisible="); pw.println(mVisible);
- pw.print(" mMinimized="); pw.println(mMinimized);
- pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
- }
-
- public long getAnimDuration() {
- float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- com.android.internal.R.dimen
- .config_appTransitionAnimationDurationScaleDefault));
- final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
- return (long) (transitionDuration * transitionScale);
- }
-
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- listener.accept(isDividerVisible());
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.add(new WeakReference<>(listener));
- }
- }
-
- public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
- synchronized (mDockedStackExistsListeners) {
- for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
- if (mDockedStackExistsListeners.get(i) == listener) {
- mDockedStackExistsListeners.remove(i);
- }
- }
- }
- }
-
- public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
- synchronized (mBoundsChangedListeners) {
- mBoundsChangedListeners.add(new WeakReference<>(listener));
- }
- }
-
- public boolean splitPrimaryTask() {
- try {
- if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED) {
- return false;
- }
- } catch (RemoteException e) {
- return false;
- }
- if (isSplitActive() || mSplits.mPrimary == null) {
- return false;
- }
-
- // Try fetching the top running task.
- final List<RunningTaskInfo> runningTasks =
- ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
- if (runningTasks == null || runningTasks.isEmpty()) {
- return false;
- }
- // Note: The set of running tasks from the system is ordered by recency.
- final RunningTaskInfo topRunningTask = runningTasks.get(0);
- final int activityType = topRunningTask.getActivityType();
- if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
- return false;
- }
-
- if (!topRunningTask.supportsSplitScreenMultiWindow) {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- return false;
- }
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Clear out current windowing mode before reparenting to split task.
- wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED);
- wct.reparent(topRunningTask.token, mSplits.mPrimary.token, true /* onTop */);
- mWindowManagerProxy.applySyncTransaction(wct);
- return true;
- }
-
- public void dismissSplitToPrimaryTask() {
- startDismissSplit(true /* toPrimaryTask */);
- }
-
- /** Notifies the bounds of split screen changed. */
- public void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
- synchronized (mBoundsChangedListeners) {
- mBoundsChangedListeners.removeIf(wf -> {
- BiConsumer<Rect, Rect> l = wf.get();
- if (l != null) l.accept(secondaryWindowBounds, secondaryWindowInsets);
- return l == null;
- });
- }
- }
-
- public void startEnterSplit() {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- // Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits,
- mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout);
- }
-
- public void prepareEnterSplitTransition(WindowContainerTransaction outWct) {
- // Set resizable directly here because buildEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.buildEnterSplit(outWct, mSplits,
- mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout);
- }
-
- public void finishEnterSplitTransition(boolean minimized) {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- if (minimized) {
- ensureMinimizedSplit();
- } else {
- ensureNormalSplit();
- }
- }
-
- public void startDismissSplit(boolean toPrimaryTask) {
- startDismissSplit(toPrimaryTask, false /* snapped */);
- }
-
- public void startDismissSplit(boolean toPrimaryTask, boolean snapped) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mSplits.getSplitTransitions().dismissSplit(
- mSplits, mSplitLayout, !toPrimaryTask, snapped);
- } else {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
- onDismissSplit();
- }
- }
-
- public void onDismissSplit() {
- updateVisibility(false /* visible */);
- mMinimized = false;
- // Resets divider bar position to undefined, so new divider bar will apply default position
- // next time entering split mode.
- mDividerState.mRatioPositionBeforeMinimized = 0;
- removeDivider();
- mImePositionProcessor.reset();
- }
-
- public void ensureMinimizedSplit() {
- setHomeMinimized(true /* minimized */);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode yet, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " entering split mode with minimized=true");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- public void ensureNormalSplit() {
- setHomeMinimized(false /* minimized */);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " enter split mode unminimized ");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- public LegacySplitDisplayLayout getSplitLayout() {
- return mSplitLayout;
- }
-
- public WindowManagerProxy getWmProxy() {
- return mWindowManagerProxy;
- }
-
- public WindowContainerToken getSecondaryRoot() {
- if (mSplits == null || mSplits.mSecondary == null) {
- return null;
- }
- return mSplits.mSecondary.token;
- }
-
- private class SplitScreenImpl implements LegacySplitScreen {
- @Override
- public boolean isMinimized() {
- return mMinimized;
- }
-
- @Override
- public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- /**
- * TODO: Remove usage from outside the shell.
- */
- @Override
- public DividerView getDividerView() {
- return LegacySplitScreenController.this.getDividerView();
- }
-
- @Override
- public boolean isDividerVisible() {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.isDividerVisible();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to get divider visible");
- }
- return result[0];
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean isShowing) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onKeyguardVisibilityChanged(isShowing);
- });
- }
-
- @Override
- public void setMinimized(boolean minimized) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.setMinimized(minimized);
- });
- }
-
- @Override
- public void onUndockingTask() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onUndockingTask();
- });
- }
-
- @Override
- public void onAppTransitionFinished() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.onAppTransitionFinished();
- });
- }
-
- @Override
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.registerInSplitScreenListener(listener);
- });
- }
-
- @Override
- public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.unregisterInSplitScreenListener(listener);
- });
- }
-
- @Override
- public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.registerBoundsChangeListener(listener);
- });
- }
-
- @Override
- public WindowContainerToken getSecondaryRoot() {
- WindowContainerToken[] result = new WindowContainerToken[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.getSecondaryRoot();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to get secondary root");
- }
- return result[0];
- }
-
- @Override
- public boolean splitPrimaryTask() {
- boolean[] result = new boolean[1];
- try {
- mMainExecutor.executeBlocking(() -> {
- result[0] = LegacySplitScreenController.this.splitPrimaryTask();
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to split primary task");
- }
- return result[0];
- }
-
- @Override
- public void dismissSplitToPrimaryTask() {
- mMainExecutor.execute(() -> {
- LegacySplitScreenController.this.dismissSplitToPrimaryTask();
- });
- }
-
- @Override
- public void dump(PrintWriter pw) {
- try {
- mMainExecutor.executeBlocking(() -> {
- LegacySplitScreenController.this.dump(pw);
- });
- } catch (InterruptedException e) {
- Slog.e(TAG, "Failed to dump LegacySplitScreenController in 2s");
- }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
deleted file mode 100644
index d2f42c39acd5..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ /dev/null
@@ -1,376 +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.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.TaskOrganizer;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SurfaceUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
- private static final String TAG = LegacySplitScreenTaskListener.class.getSimpleName();
- private static final boolean DEBUG = LegacySplitScreenController.DEBUG;
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final SyncTransactionQueue mSyncQueue;
- private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
-
- // TODO(shell-transitions): Remove when switched to shell-transitions.
- private final SparseArray<Point> mPositionByTaskId = new SparseArray<>();
-
- RunningTaskInfo mPrimary;
- RunningTaskInfo mSecondary;
- SurfaceControl mPrimarySurface;
- SurfaceControl mSecondarySurface;
- SurfaceControl mPrimaryDim;
- SurfaceControl mSecondaryDim;
- Rect mHomeBounds = new Rect();
- final LegacySplitScreenController mSplitScreenController;
- private boolean mSplitScreenSupported = false;
-
- final SurfaceSession mSurfaceSession = new SurfaceSession();
-
- private final LegacySplitScreenTransitions mSplitTransitions;
-
- LegacySplitScreenTaskListener(LegacySplitScreenController splitScreenController,
- ShellTaskOrganizer shellTaskOrganizer,
- Transitions transitions,
- SyncTransactionQueue syncQueue) {
- mSplitScreenController = splitScreenController;
- mTaskOrganizer = shellTaskOrganizer;
- mSplitTransitions = new LegacySplitScreenTransitions(splitScreenController.mTransactionPool,
- transitions, mSplitScreenController, this);
- transitions.addHandler(mSplitTransitions);
- mSyncQueue = syncQueue;
- }
-
- void init() {
- synchronized (this) {
- try {
- mTaskOrganizer.createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, this);
- mTaskOrganizer.createRootTask(
- DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, this);
- } catch (Exception e) {
- // teardown to prevent callbacks
- mTaskOrganizer.removeListener(this);
- throw e;
- }
- }
- }
-
- boolean isSplitScreenSupported() {
- return mSplitScreenSupported;
- }
-
- SurfaceControl.Transaction getTransaction() {
- return mSplitScreenController.mTransactionPool.acquire();
- }
-
- void releaseTransaction(SurfaceControl.Transaction t) {
- mSplitScreenController.mTransactionPool.release(t);
- }
-
- TaskOrganizer getTaskOrganizer() {
- return mTaskOrganizer;
- }
-
- LegacySplitScreenTransitions getSplitTransitions() {
- return mSplitTransitions;
- }
-
- @Override
- public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
- synchronized (this) {
- if (taskInfo.hasParentTask()) {
- handleChildTaskAppeared(taskInfo, leash);
- return;
- }
-
- final int winMode = taskInfo.getWindowingMode();
- if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- ProtoLog.v(WM_SHELL_TASK_ORG,
- "%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
- mPrimary = taskInfo;
- mPrimarySurface = leash;
- } else if (winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- ProtoLog.v(WM_SHELL_TASK_ORG,
- "%s onTaskAppeared Secondary taskId=%d", TAG, taskInfo.taskId);
- mSecondary = taskInfo;
- mSecondarySurface = leash;
- } else {
- ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared unknown taskId=%d winMode=%d",
- TAG, taskInfo.taskId, winMode);
- }
-
- if (!mSplitScreenSupported && mPrimarySurface != null && mSecondarySurface != null) {
- mSplitScreenSupported = true;
- mSplitScreenController.onSplitScreenSupported();
- ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG);
-
- // Initialize dim surfaces:
- SurfaceControl.Transaction t = getTransaction();
- mPrimaryDim = SurfaceUtils.makeDimLayer(
- t, mPrimarySurface, "Primary Divider Dim", mSurfaceSession);
- mSecondaryDim = SurfaceUtils.makeDimLayer(
- t, mSecondarySurface, "Secondary Divider Dim", mSurfaceSession);
- t.apply();
- releaseTransaction(t);
- }
- }
- }
-
- @Override
- public void onTaskVanished(RunningTaskInfo taskInfo) {
- synchronized (this) {
- mPositionByTaskId.remove(taskInfo.taskId);
- if (taskInfo.hasParentTask()) {
- mLeashByTaskId.remove(taskInfo.taskId);
- return;
- }
-
- final boolean isPrimaryTask = mPrimary != null
- && taskInfo.token.equals(mPrimary.token);
- final boolean isSecondaryTask = mSecondary != null
- && taskInfo.token.equals(mSecondary.token);
-
- if (mSplitScreenSupported && (isPrimaryTask || isSecondaryTask)) {
- mSplitScreenSupported = false;
-
- SurfaceControl.Transaction t = getTransaction();
- t.remove(mPrimaryDim);
- t.remove(mSecondaryDim);
- t.remove(mPrimarySurface);
- t.remove(mSecondarySurface);
- t.apply();
- releaseTransaction(t);
-
- mSplitScreenController.onTaskVanished();
- }
- }
- }
-
- @Override
- public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
- if (taskInfo.displayId != DEFAULT_DISPLAY) {
- return;
- }
- synchronized (this) {
- if (!taskInfo.supportsMultiWindow) {
- if (mSplitScreenController.isDividerVisible()) {
- // Dismiss the split screen if the task no longer supports multi window.
- if (taskInfo.taskId == mPrimary.taskId
- || taskInfo.parentTaskId == mPrimary.taskId) {
- // If the primary is focused, dismiss to primary.
- mSplitScreenController
- .startDismissSplit(taskInfo.isFocused /* toPrimaryTask */);
- } else {
- // If the secondary is not focused, dismiss to primary.
- mSplitScreenController
- .startDismissSplit(!taskInfo.isFocused /* toPrimaryTask */);
- }
- }
- return;
- }
- if (taskInfo.hasParentTask()) {
- // changed messages are noisy since it reports on every ensureVisibility. This
- // conflicts with legacy app-transitions which "swaps" the position to a
- // leash. For now, only update when position actually changes to avoid
- // poorly-timed duplicate calls.
- if (taskInfo.positionInParent.equals(mPositionByTaskId.get(taskInfo.taskId))) {
- return;
- }
- handleChildTaskChanged(taskInfo);
- } else {
- handleTaskInfoChanged(taskInfo);
- }
- mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
- }
- }
-
- private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
- mLeashByTaskId.put(taskInfo.taskId, leash);
- mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
- }
-
- private void handleChildTaskChanged(RunningTaskInfo taskInfo) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
- updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
- }
-
- private void updateChildTaskSurface(
- RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) {
- final Point taskPositionInParent = taskInfo.positionInParent;
- mSyncQueue.runInSync(t -> {
- t.setWindowCrop(leash, null);
- t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
- if (firstAppeared && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- }
- });
- }
-
- /**
- * This is effectively a finite state machine which moves between the various split-screen
- * presentations based on the contents of the split regions.
- */
- private void handleTaskInfoChanged(RunningTaskInfo info) {
- if (!mSplitScreenSupported) {
- // This shouldn't happen; but apparently there is a chance that SysUI crashes without
- // system server receiving binder-death (or maybe it receives binder-death too late?).
- // In this situation, when sys-ui restarts, the split root-tasks will still exist so
- // there is a small window of time during init() where WM might send messages here
- // before init() fails. So, avoid a cycle of crashes by returning early.
- Log.e(TAG, "Got handleTaskInfoChanged when not initialized: " + info);
- return;
- }
- final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
- || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mSplitScreenController.isHomeStackResizable());
- final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- if (info.token.asBinder() == mPrimary.token.asBinder()) {
- mPrimary = info;
- } else if (info.token.asBinder() == mSecondary.token.asBinder()) {
- mSecondary = info;
- }
- if (DEBUG) {
- Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
- }
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final boolean primaryIsEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
- final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
- || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mSplitScreenController.isHomeStackResizable());
- if (primaryIsEmpty == primaryWasEmpty && secondaryWasEmpty == secondaryIsEmpty
- && secondaryImpliedMinimize == secondaryImpliesMinimize) {
- // No relevant changes
- return;
- }
- if (primaryIsEmpty || secondaryIsEmpty) {
- // At-least one of the splits is empty which means we are currently transitioning
- // into or out-of split-screen mode.
- if (DEBUG) {
- Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
- + " " + mSecondary.topActivityType);
- }
- if (mSplitScreenController.isDividerVisible()) {
- // Was in split-mode, which means we are leaving split, so continue that.
- // This happens when the stack in the primary-split is dismissed.
- if (DEBUG) {
- Log.d(TAG, " was in split, so this means leave it "
- + mPrimary.topActivityType + " " + mSecondary.topActivityType);
- }
- mSplitScreenController.startDismissSplit(false /* toPrimaryTask */);
- } else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
- // Wasn't in split-mode (both were empty), but now that the primary split is
- // populated, we should fully enter split by moving everything else into secondary.
- // This just tells window-manager to reparent things, the UI will respond
- // when it gets new task info for the secondary split.
- if (DEBUG) {
- Log.d(TAG, " was not in split, but primary is populated, so enter it");
- }
- mSplitScreenController.startEnterSplit();
- }
- } else if (secondaryImpliesMinimize) {
- // Workaround for b/172686383, we can't rely on the sync bounds change transaction for
- // the home task to finish before the last updateChildTaskSurface() call even if it's
- // queued on the sync transaction queue, so ensure that the home task surface is updated
- // again before we minimize
- final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
- mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks,
- mSplitScreenController.getSecondaryRoot());
- for (int i = 0; i < tasks.size(); i++) {
- final RunningTaskInfo taskInfo = tasks.get(i);
- final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
- if (leash != null) {
- updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
- }
- }
-
- // Both splits are populated but the secondary split has a home/recents stack on top,
- // so enter minimized mode.
- mSplitScreenController.ensureMinimizedSplit();
- } else {
- // Both splits are populated by normal activities, so make sure we aren't minimized.
- mSplitScreenController.ensureNormalSplit();
- }
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- b.setParent(findTaskSurface(taskId));
- }
-
- @Override
- public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
- SurfaceControl.Transaction t) {
- t.reparent(sc, findTaskSurface(taskId));
- }
-
- private SurfaceControl findTaskSurface(int taskId) {
- if (!mLeashByTaskId.contains(taskId)) {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- return mLeashByTaskId.get(taskId);
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- pw.println(innerPrefix + "mSplitScreenSupported=" + mSplitScreenSupported);
- if (mPrimary != null) pw.println(innerPrefix + "mPrimary.taskId=" + mPrimary.taskId);
- if (mSecondary != null) pw.println(innerPrefix + "mSecondary.taskId=" + mSecondary.taskId);
- }
-
- @Override
- public String toString() {
- return TAG;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
deleted file mode 100644
index b1fa2ac25fe7..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
+++ /dev/null
@@ -1,348 +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.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.WindowConfiguration;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-
-/** Plays transition animations for split-screen */
-public class LegacySplitScreenTransitions implements Transitions.TransitionHandler {
- private static final String TAG = "SplitScreenTransitions";
-
- public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 10;
-
- private final TransactionPool mTransactionPool;
- private final Transitions mTransitions;
- private final LegacySplitScreenController mSplitScreen;
- private final LegacySplitScreenTaskListener mListener;
-
- private IBinder mPendingDismiss = null;
- private boolean mDismissFromSnap = false;
- private IBinder mPendingEnter = null;
- private IBinder mAnimatingTransition = null;
-
- /** Keeps track of currently running animations */
- private final ArrayList<Animator> mAnimations = new ArrayList<>();
-
- private Transitions.TransitionFinishCallback mFinishCallback = null;
- private SurfaceControl.Transaction mFinishTransaction;
-
- LegacySplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
- @NonNull LegacySplitScreenController splitScreen,
- @NonNull LegacySplitScreenTaskListener listener) {
- mTransactionPool = pool;
- mTransitions = transitions;
- mSplitScreen = splitScreen;
- mListener = listener;
- }
-
- @Override
- public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
- @Nullable TransitionRequestInfo request) {
- WindowContainerTransaction out = null;
- final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
- final @WindowManager.TransitionType int type = request.getType();
- if (mSplitScreen.isDividerVisible()) {
- // try to handle everything while in split-screen
- out = new WindowContainerTransaction();
- if (triggerTask != null) {
- final boolean shouldDismiss =
- // if we close the primary-docked task, then leave split-screen since there
- // is nothing behind it.
- ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK)
- && triggerTask.parentTaskId == mListener.mPrimary.taskId)
- // if an activity that is not supported in multi window mode is launched,
- // we also need to leave split-screen.
- || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
- && !triggerTask.supportsMultiWindow);
- // In both cases, dismiss the primary
- if (shouldDismiss) {
- WindowManagerProxy.buildDismissSplit(out, mListener,
- mSplitScreen.getSplitLayout(), true /* dismiss */);
- if (type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) {
- out.reorder(triggerTask.token, true /* onTop */);
- }
- mPendingDismiss = transition;
- }
- }
- } else if (triggerTask != null) {
- // Not in split mode, so look for an open with a trigger task.
- if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
- && triggerTask.configuration.windowConfiguration.getWindowingMode()
- == WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- out = new WindowContainerTransaction();
- mSplitScreen.prepareEnterSplitTransition(out);
- mPendingEnter = transition;
- }
- }
- return out;
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) {
- final float end = show ? 1.f : 0.f;
- final float start = 1.f - end;
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(start, end);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setAlpha(leash, end);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) { }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) { }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleResizeAnimation(@NonNull SurfaceControl leash,
- @NonNull Rect startBounds, @NonNull Rect endBounds) {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setWindowCrop(leash,
- (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction),
- (int) (startBounds.height() * (1.f - fraction)
- + endBounds.height() * fraction));
- transaction.setPosition(leash,
- startBounds.left * (1.f - fraction) + endBounds.left * fraction,
- startBounds.top * (1.f - fraction) + endBounds.top * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setWindowCrop(leash, 0, 0);
- transaction.setPosition(leash, endBounds.left, endBounds.top);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-
- @Override
- public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (transition != mPendingDismiss && transition != mPendingEnter) {
- // If we're not in split-mode, just abort
- if (!mSplitScreen.isDividerVisible()) return false;
- // Check to see if HOME is involved
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() == null
- || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) continue;
- if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
- mSplitScreen.ensureMinimizedSplit();
- } else if (change.getMode() == TRANSIT_CLOSE
- || change.getMode() == TRANSIT_TO_BACK) {
- mSplitScreen.ensureNormalSplit();
- }
- }
- // Use normal animations.
- return false;
- }
-
- mFinishCallback = finishCallback;
- mFinishTransaction = mTransactionPool.acquire();
- mAnimatingTransition = transition;
-
- // Play fade animations
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final SurfaceControl leash = change.getLeash();
- final int mode = info.getChanges().get(i).getMode();
-
- if (mode == TRANSIT_CHANGE) {
- if (change.getParent() != null) {
- // This is probably reparented, so we want the parent to be immediately visible
- final TransitionInfo.Change parentChange = info.getChange(change.getParent());
- startTransaction.show(parentChange.getLeash());
- startTransaction.setAlpha(parentChange.getLeash(), 1.f);
- // and then animate this layer outside the parent (since, for example, this is
- // the home task animating from fullscreen to part-screen).
- startTransaction.reparent(leash, info.getRootLeash());
- startTransaction.setLayer(leash, info.getChanges().size() - i);
- // build the finish reparent/reposition
- mFinishTransaction.reparent(leash, parentChange.getLeash());
- mFinishTransaction.setPosition(leash,
- change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- // TODO(shell-transitions): screenshot here
- final Rect startBounds = new Rect(change.getStartAbsBounds());
- final boolean isHome = change.getTaskInfo() != null
- && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME;
- if (mPendingDismiss == transition && mDismissFromSnap && !isHome) {
- // Home is special since it doesn't move during fling. Everything else, though,
- // when dismissing from snap, the top/left is at 0,0.
- startBounds.offsetTo(0, 0);
- }
- final Rect endBounds = new Rect(change.getEndAbsBounds());
- startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- startExampleResizeAnimation(leash, startBounds, endBounds);
- }
- if (change.getParent() != null) {
- continue;
- }
-
- if (transition == mPendingEnter
- && mListener.mPrimary.token.equals(change.getContainer())
- || mListener.mSecondary.token.equals(change.getContainer())) {
- startTransaction.setWindowCrop(leash, change.getStartAbsBounds().width(),
- change.getStartAbsBounds().height());
- if (mListener.mPrimary.token.equals(change.getContainer())) {
- // Move layer to top since we want it above the oversized home task during
- // animation even though home task is on top in hierarchy.
- startTransaction.setLayer(leash, info.getChanges().size() + 1);
- }
- }
- boolean isOpening = Transitions.isOpeningType(info.getType());
- if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
- // fade in
- startExampleAnimation(leash, true /* show */);
- } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
- // fade out
- if (transition == mPendingDismiss && mDismissFromSnap) {
- // Dismissing via snap-to-top/bottom means that the dismissed task is already
- // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
- // and don't animate it so it doesn't pop-in when reparented.
- startTransaction.setAlpha(leash, 0.f);
- } else {
- startExampleAnimation(leash, false /* show */);
- }
- }
- }
- if (transition == mPendingEnter) {
- // If entering, check if we should enter into minimized or normal split
- boolean homeIsVisible = false;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() == null
- || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) {
- continue;
- }
- homeIsVisible = change.getMode() == TRANSIT_OPEN
- || change.getMode() == TRANSIT_TO_FRONT
- || change.getMode() == TRANSIT_CHANGE;
- break;
- }
- mSplitScreen.finishEnterSplitTransition(homeIsVisible);
- }
- startTransaction.apply();
- onFinish();
- return true;
- }
-
- @ExternalThread
- void dismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize, boolean snapped) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- WindowManagerProxy.buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
- mTransitions.getMainExecutor().execute(() -> {
- mDismissFromSnap = snapped;
- mPendingDismiss = mTransitions.startTransition(TRANSIT_SPLIT_DISMISS_SNAP, wct, this);
- });
- }
-
- private void onFinish() {
- if (!mAnimations.isEmpty()) return;
- mFinishTransaction.apply();
- mTransactionPool.release(mFinishTransaction);
- mFinishTransaction = null;
- mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
- mFinishCallback = null;
- if (mAnimatingTransition == mPendingEnter) {
- mPendingEnter = null;
- }
- if (mAnimatingTransition == mPendingDismiss) {
- mSplitScreen.onDismissSplit();
- mPendingDismiss = null;
- }
- mDismissFromSnap = false;
- mAnimatingTransition = null;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java
deleted file mode 100644
index 1e9223cbe3e2..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 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.legacysplitscreen;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.Shader;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.wm.shell.R;
-
-/**
- * Shadow for the minimized dock state on homescreen.
- */
-public class MinimizedDockShadow extends View {
-
- private final Paint mShadowPaint = new Paint();
-
- private int mDockSide = WindowManager.DOCKED_INVALID;
-
- public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- void setDockSide(int dockSide) {
- if (dockSide != mDockSide) {
- mDockSide = dockSide;
- updatePaint(getLeft(), getTop(), getRight(), getBottom());
- invalidate();
- }
- }
-
- private void updatePaint(int left, int top, int right, int bottom) {
- int startColor = mContext.getResources().getColor(
- R.color.minimize_dock_shadow_start, null);
- int endColor = mContext.getResources().getColor(
- R.color.minimize_dock_shadow_end, null);
- final int middleColor = Color.argb(
- (Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0);
- final int quarter = Color.argb(
- (int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f),
- 0, 0, 0);
- if (mDockSide == WindowManager.DOCKED_TOP) {
- mShadowPaint.setShader(new LinearGradient(
- 0, 0, 0, bottom - top,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- } else if (mDockSide == WindowManager.DOCKED_LEFT) {
- mShadowPaint.setShader(new LinearGradient(
- 0, 0, right - left, 0,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
- mShadowPaint.setShader(new LinearGradient(
- right - left, 0, 0, 0,
- new int[] { startColor, middleColor, quarter, endColor },
- new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- updatePaint(left, top, right, bottom);
- invalidate();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
deleted file mode 100644
index e42e43bbc2be..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2015 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.legacysplitscreen;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.Display;
-import android.view.SurfaceControl;
-import android.view.WindowManagerGlobal;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Proxy to simplify calls into window manager/activity manager
- */
-class WindowManagerProxy {
-
- private static final String TAG = "WindowManagerProxy";
- private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
- private static final int[] CONTROLLED_ACTIVITY_TYPES = {
- ACTIVITY_TYPE_STANDARD,
- ACTIVITY_TYPE_HOME,
- ACTIVITY_TYPE_RECENTS,
- ACTIVITY_TYPE_UNDEFINED
- };
- private static final int[] CONTROLLED_WINDOWING_MODES = {
- WINDOWING_MODE_FULLSCREEN,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- WINDOWING_MODE_UNDEFINED
- };
-
- @GuardedBy("mDockedRect")
- private final Rect mDockedRect = new Rect();
-
- private final Rect mTmpRect1 = new Rect();
-
- @GuardedBy("mDockedRect")
- private final Rect mTouchableRegion = new Rect();
-
- private final SyncTransactionQueue mSyncTransactionQueue;
- private final TaskOrganizer mTaskOrganizer;
-
- WindowManagerProxy(SyncTransactionQueue syncQueue, TaskOrganizer taskOrganizer) {
- mSyncTransactionQueue = syncQueue;
- mTaskOrganizer = taskOrganizer;
- }
-
- void dismissOrMaximizeDocked(final LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout layout, final boolean dismissOrMaximize) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- tiles.mSplitScreenController.startDismissSplit(!dismissOrMaximize, true /* snapped */);
- } else {
- applyDismissSplit(tiles, layout, dismissOrMaximize);
- }
- }
-
- public void setResizing(final boolean resizing) {
- try {
- ActivityTaskManager.getService().setSplitScreenResizing(resizing);
- } catch (RemoteException e) {
- Log.w(TAG, "Error calling setDockedStackResizing: " + e);
- }
- }
-
- /** Sets a touch region */
- public void setTouchRegion(Rect region) {
- try {
- synchronized (mDockedRect) {
- mTouchableRegion.set(region);
- }
- WindowManagerGlobal.getWindowManagerService().setDockedTaskDividerTouchRegion(
- mTouchableRegion);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set touchable region: " + e);
- }
- }
-
- void applyResizeSplits(int position, LegacySplitDisplayLayout splitLayout) {
- WindowContainerTransaction t = new WindowContainerTransaction();
- splitLayout.resizeSplits(position, t);
- applySyncTransaction(t);
- }
-
- boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
- WindowContainerToken parent) {
- boolean resizable = false;
- List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
- ? mTaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS)
- : mTaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS);
- for (int i = 0, n = rootTasks.size(); i < n; ++i) {
- final ActivityManager.RunningTaskInfo ti = rootTasks.get(i);
- out.add(ti);
- if (ti.topActivityType == ACTIVITY_TYPE_HOME) {
- resizable = ti.isResizeable;
- }
- }
- return resizable;
- }
-
- /**
- * Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
- * split is minimized. This actually "sticks out" of the secondary split area, but when in
- * minimized mode, the secondary split gets a 'negative' crop to expose it.
- */
- boolean applyHomeTasksMinimized(LegacySplitDisplayLayout layout, WindowContainerToken parent,
- @NonNull WindowContainerTransaction wct) {
- // Resize the home/recents stacks to the larger minimized-state size
- final Rect homeBounds;
- final ArrayList<ActivityManager.RunningTaskInfo> homeStacks = new ArrayList<>();
- boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent);
- if (isHomeResizable) {
- homeBounds = layout.calcResizableMinimizedHomeStackBounds();
- } else {
- // home is not resizable, so lock it to its inherent orientation size.
- homeBounds = new Rect(0, 0, 0, 0);
- for (int i = homeStacks.size() - 1; i >= 0; --i) {
- if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_HOME) {
- final int orient = homeStacks.get(i).configuration.orientation;
- final boolean displayLandscape = layout.mDisplayLayout.isLandscape();
- final boolean isLandscape = orient == ORIENTATION_LANDSCAPE
- || (orient == ORIENTATION_UNDEFINED && displayLandscape);
- homeBounds.right = isLandscape == displayLandscape
- ? layout.mDisplayLayout.width() : layout.mDisplayLayout.height();
- homeBounds.bottom = isLandscape == displayLandscape
- ? layout.mDisplayLayout.height() : layout.mDisplayLayout.width();
- break;
- }
- }
- }
- for (int i = homeStacks.size() - 1; i >= 0; --i) {
- // For non-resizable homes, the minimized size is actually the fullscreen-size. As a
- // result, we don't minimize for recents since it only shows half-size screenshots.
- if (!isHomeResizable) {
- if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_RECENTS) {
- continue;
- }
- wct.setWindowingMode(homeStacks.get(i).token, WINDOWING_MODE_FULLSCREEN);
- }
- wct.setBounds(homeStacks.get(i).token, homeBounds);
- }
- layout.mTiles.mHomeBounds.set(homeBounds);
- return isHomeResizable;
- }
-
- /** @see #buildEnterSplit */
- boolean applyEnterSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout) {
- // Set launchtile first so that any stack created after
- // getAllRootTaskInfos and before reparent (even if unlikely) are placed
- // correctly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setLaunchRoot(tiles.mSecondary.token, CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES);
- final boolean isHomeResizable = buildEnterSplit(wct, tiles, layout);
- applySyncTransaction(wct);
- return isHomeResizable;
- }
-
- /**
- * Finishes entering split-screen by reparenting all FULLSCREEN tasks into the secondary split.
- * This assumes there is already something in the primary split since that is usually what
- * triggers a call to this. In the same transaction, this overrides the home task bounds via
- * {@link #applyHomeTasksMinimized}.
- *
- * @return whether the home stack is resizable
- */
- boolean buildEnterSplit(WindowContainerTransaction outWct, LegacySplitScreenTaskListener tiles,
- LegacySplitDisplayLayout layout) {
- List<ActivityManager.RunningTaskInfo> rootTasks =
- mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
- if (rootTasks.isEmpty()) {
- return false;
- }
- ActivityManager.RunningTaskInfo topHomeTask = null;
- for (int i = rootTasks.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
- // Check whether the task can be moved to split secondary.
- if (!rootTask.supportsMultiWindow && rootTask.topActivityType != ACTIVITY_TYPE_HOME) {
- continue;
- }
- // Only move split controlling tasks to split secondary.
- final int windowingMode = rootTask.getWindowingMode();
- if (!ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, windowingMode)
- || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, rootTask.getActivityType())
- // Excludes split screen secondary due to it's the root we're reparenting to.
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- continue;
- }
- // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
- // so it will be left with the status of the top one.
- topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
- outWct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
- }
- // Move the secondary split-forward.
- outWct.reorder(tiles.mSecondary.token, true /* onTop */);
- boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */,
- outWct);
- if (topHomeTask != null && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
- // is enabled, this temporarily syncs the home surface position with offset until
- // sync transaction finishes.
- outWct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
- }
- return isHomeResizable;
- }
-
- static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
- final int atype = ti.getActivityType();
- return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
- }
-
- /** @see #buildDismissSplit */
- void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize) {
- // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
- // plus specific APIs to clean this up.
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Set launch root first so that any task created after getChildContainers and
- // before reparent (pretty unlikely) are put into fullscreen.
- wct.setLaunchRoot(tiles.mSecondary.token, null, null);
- buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
- applySyncTransaction(wct);
- }
-
- /**
- * Reparents all tile members back to their display and resets home task override bounds.
- * @param dismissOrMaximize When {@code true} this resolves the split by closing the primary
- * split (thus resulting in the top of the secondary split becoming
- * fullscreen. {@code false} resolves the other way.
- */
- static void buildDismissSplit(WindowContainerTransaction outWct,
- LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
- boolean dismissOrMaximize) {
- // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
- // plus specific APIs to clean this up.
- final TaskOrganizer taskOrg = tiles.getTaskOrganizer();
- List<ActivityManager.RunningTaskInfo> primaryChildren =
- taskOrg.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
- List<ActivityManager.RunningTaskInfo> secondaryChildren =
- taskOrg.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
- // In some cases (eg. non-resizable is launched), system-server will leave split-screen.
- // as a result, the above will not capture any tasks; yet, we need to clean-up the
- // home task bounds.
- List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
- taskOrg.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS);
- // Filter out the root split tasks
- freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token)
- || p.token.equals(tiles.mPrimary.token));
-
- if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
- && freeHomeAndRecents.isEmpty()) {
- return;
- }
- if (dismissOrMaximize) {
- // Dismissing, so move all primary split tasks first
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- outWct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- boolean homeOnTop = false;
- // Don't need to worry about home tasks because they are already in the "proper"
- // order within the secondary split.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- outWct.reparent(ti.token, null /* parent */, true /* onTop */);
- if (isHomeOrRecentTask(ti)) {
- outWct.setBounds(ti.token, null);
- outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
- if (i == 0) {
- homeOnTop = true;
- }
- }
- }
- if (homeOnTop && !Transitions.ENABLE_SHELL_TRANSITIONS) {
- // Translate/update-crop of secondary out-of-band with sync transaction -- instead
- // play this in sync with new home-app frame because until BALST is enabled this
- // shows up on screen before the syncTransaction returns.
- // We only have access to the secondary root surface, though, so in order to
- // position things properly, we have to take into account the existing negative
- // offset/crop of the minimized-home task.
- final boolean landscape = layout.mDisplayLayout.isLandscape();
- final int posX = landscape ? layout.mSecondary.left - tiles.mHomeBounds.left
- : layout.mSecondary.left;
- final int posY = landscape ? layout.mSecondary.top
- : layout.mSecondary.top - tiles.mHomeBounds.top;
- final SurfaceControl.Transaction sft = new SurfaceControl.Transaction();
- sft.setPosition(tiles.mSecondarySurface, posX, posY);
- final Rect crop = new Rect(0, 0, layout.mDisplayLayout.width(),
- layout.mDisplayLayout.height());
- crop.offset(-posX, -posY);
- sft.setWindowCrop(tiles.mSecondarySurface, crop);
- outWct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
- }
- } else {
- // Maximize, so move non-home secondary split first
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- if (isHomeOrRecentTask(secondaryChildren.get(i))) {
- continue;
- }
- outWct.reparent(secondaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- // Find and place home tasks in-between. This simulates the fact that there was
- // nothing behind the primary split's tasks.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- if (isHomeOrRecentTask(ti)) {
- outWct.reparent(ti.token, null /* parent */, true /* onTop */);
- // reset bounds and mode too
- outWct.setBounds(ti.token, null);
- outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
- }
- }
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- outWct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- }
- for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
- outWct.setBounds(freeHomeAndRecents.get(i).token, null);
- outWct.setWindowingMode(freeHomeAndRecents.get(i).token, WINDOWING_MODE_UNDEFINED);
- }
- // Reset focusable to true
- outWct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- }
-
- /**
- * Utility to apply a sync transaction serially with other sync transactions.
- *
- * @see SyncTransactionQueue#queue
- */
- void applySyncTransaction(WindowContainerTransaction wct) {
- mSyncTransactionQueue.queue(wct);
- }
-
- /**
- * @see SyncTransactionQueue#queueIfWaiting
- */
- boolean queueSyncTransactionIfWaiting(WindowContainerTransaction wct) {
- return mSyncTransactionQueue.queueIfWaiting(wct);
- }
-
- /**
- * @see SyncTransactionQueue#runInSync
- */
- void runInSync(SyncTransactionQueue.TransactionRunnable runnable) {
- mSyncTransactionQueue.runInSync(runnable);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 179b725ab210..1d8ac2b576e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -39,6 +39,7 @@ import android.provider.Settings;
import android.util.Slog;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -659,11 +660,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
}
/**
- * Handles rotation based on OnDisplayChangingListener callback
+ * Handles display change based on OnDisplayChangingListener callback
*/
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction wct) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
if (!isInitialized()) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e624de661737..99e7dc5065bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -297,6 +297,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
displayController.addDisplayWindowListener(this);
}
+ public PipTransitionController getTransitionController() {
+ return mPipTransitionController;
+ }
+
public Rect getCurrentOrAnimatingBounds() {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 36e712459863..28427a808d90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -28,7 +28,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
-import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
@@ -52,6 +51,7 @@ import android.graphics.Rect;
import android.os.IBinder;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
@@ -145,6 +145,11 @@ public class PipTransition extends PipTransitionController {
if (destinationBounds != null) {
mExitDestinationBounds.set(destinationBounds);
}
+ final PipAnimationController.PipTransitionAnimator animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null && animator.isRunning()) {
+ animator.cancel();
+ }
mExitTransition = mTransitions.startTransition(type, out, this);
}
@@ -217,13 +222,20 @@ public class PipTransition extends PipTransitionController {
}
// Entering PIP.
- if (isEnteringPip(info, mCurrentPipTaskToken)) {
- return startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
+ if (isEnteringPip(info)) {
+ startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
+ return true;
}
// For transition that we don't animate, but contains the PIP leash, we need to update the
// PIP surface, otherwise it will be reset after the transition.
if (currentPipTaskChange != null) {
+ // Set the "end" bounds of pip. The default setup uses the start bounds. Since this is
+ // changing the *finish*Transaction, we need to use the end bounds. This will also
+ // make sure that the fade-in animation (below) uses the end bounds as well.
+ if (!currentPipTaskChange.getEndAbsBounds().isEmpty()) {
+ mPipBoundsState.setBounds(currentPipTaskChange.getEndAbsBounds());
+ }
updatePipForUnhandledTransition(currentPipTaskChange, startTransaction,
finishTransaction);
}
@@ -245,16 +257,9 @@ public class PipTransition extends PipTransitionController {
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (request.getType() == TRANSIT_PIP) {
+ if (requestHasPipEnter(request)) {
WindowContainerTransaction wct = new WindowContainerTransaction();
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- mRequestedEnterTransition = transition;
- mRequestedEnterTask = request.getTriggerTask().token;
- wct.setActivityWindowingMode(request.getTriggerTask().token,
- WINDOWING_MODE_UNDEFINED);
- final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
- wct.setBounds(request.getTriggerTask().token, destinationBounds);
- }
+ augmentRequest(transition, request, wct);
return wct;
} else {
return null;
@@ -262,6 +267,22 @@ public class PipTransition extends PipTransitionController {
}
@Override
+ public void augmentRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
+ if (!requestHasPipEnter(request)) {
+ throw new IllegalStateException("Called PiP augmentRequest when request has no PiP");
+ }
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ mRequestedEnterTransition = transition;
+ mRequestedEnterTask = request.getTriggerTask().token;
+ outWCT.setActivityWindowingMode(request.getTriggerTask().token,
+ WINDOWING_MODE_UNDEFINED);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+ outWCT.setBounds(request.getTriggerTask().token, destinationBounds);
+ }
+ }
+
+ @Override
public boolean handleRotateDisplay(int startRotation, int endRotation,
WindowContainerTransaction wct) {
if (mRequestedEnterTransition != null && mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -315,11 +336,27 @@ public class PipTransition extends PipTransitionController {
// (likely a remote like launcher), so don't fire the finish-callback here -- wait until
// the exit transition is merged.
if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareFinishResizeTransaction(taskInfo, destinationBounds,
- direction, wct);
- if (tx != null) {
- wct.setBoundsChangeTransaction(taskInfo.token, tx);
+ WindowContainerTransaction wct = null;
+ if (isOutPipDirection(direction)) {
+ // Only need to reset surface properties. The server-side operations were already
+ // done at the start.
+ if (tx != null) {
+ mFinishTransaction.merge(tx);
+ }
+ } else {
+ wct = new WindowContainerTransaction();
+ if (isInPipDirection(direction)) {
+ // If we are animating from fullscreen using a bounds animation, then reset the
+ // activity windowing mode, and set the task bounds to the final bounds
+ wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
+ wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds);
+ wct.setBounds(taskInfo.token, destinationBounds);
+ } else {
+ wct.setBounds(taskInfo.token, null /* bounds */);
+ }
+ if (tx != null) {
+ wct.setBoundsChangeTransaction(taskInfo.token, tx);
+ }
}
final SurfaceControl leash = mPipOrganizer.getSurfaceControl();
final int displayRotation = taskInfo.getConfiguration().windowConfiguration
@@ -559,92 +596,94 @@ public class PipTransition extends PipTransitionController {
}
/** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
- private static boolean isEnteringPip(@NonNull TransitionInfo info,
- @Nullable WindowContainerToken currentPipTaskToken) {
+ private boolean isEnteringPip(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() != null
- && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
- && !change.getContainer().equals(currentPipTaskToken)) {
- // We support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
- // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
- if (info.getType() == TRANSIT_PIP || info.getType() == TRANSIT_OPEN) {
- return true;
- }
- // This can happen if the request to enter PIP happens when we are collecting for
- // another transition, such as TRANSIT_CHANGE (display rotation).
- if (info.getType() == TRANSIT_CHANGE) {
- return true;
- }
+ if (isEnteringPip(change, info.getType())) return true;
+ }
+ return false;
+ }
- // Please file a bug to handle the unexpected transition type.
- throw new IllegalStateException("Entering PIP with unexpected transition type="
- + transitTypeToString(info.getType()));
+ /** Whether a particular change is a window that is entering pip. */
+ @Override
+ public boolean isEnteringPip(@NonNull TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
+ && !change.getContainer().equals(mCurrentPipTaskToken)) {
+ // We support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
+ // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
+ if (transitType == TRANSIT_PIP || transitType == TRANSIT_OPEN) {
+ return true;
+ }
+ // This can happen if the request to enter PIP happens when we are collecting for
+ // another transition, such as TRANSIT_CHANGE (display rotation).
+ if (transitType == TRANSIT_CHANGE) {
+ return true;
}
+
+ // Please file a bug to handle the unexpected transition type.
+ throw new IllegalStateException("Entering PIP with unexpected transition type="
+ + transitTypeToString(transitType));
}
return false;
}
- private boolean startEnterAnimation(@NonNull TransitionInfo info,
+ private void startEnterAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- // Search for an Enter PiP transition (along with a show wallpaper one)
+ // Search for an Enter PiP transition
TransitionInfo.Change enterPip = null;
- TransitionInfo.Change wallpaper = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getTaskInfo() != null
&& change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
enterPip = change;
- } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
- wallpaper = change;
}
}
if (enterPip == null) {
- return false;
- }
- // Keep track of the PIP task.
- mCurrentPipTaskToken = enterPip.getContainer();
- mHasFadeOut = false;
-
- if (mFinishCallback != null) {
- callFinishCallback(null /* wct */);
- mFinishTransaction = null;
- throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ throw new IllegalStateException("Trying to start PiP animation without a pip"
+ + "participant");
}
- // Show the wallpaper if there is a wallpaper change.
- if (wallpaper != null) {
- startTransaction.show(wallpaper.getLeash());
- startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
- }
// Make sure other open changes are visible as entering PIP. Some may be hidden in
// Transitions#setupStartState because the transition type is OPEN (such as auto-enter).
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change == enterPip || change == wallpaper) {
- continue;
- }
+ if (change == enterPip) continue;
if (isOpeningType(change.getMode())) {
final SurfaceControl leash = change.getLeash();
startTransaction.show(leash).setAlpha(leash, 1.f);
}
}
+ startEnterAnimation(enterPip, startTransaction, finishTransaction, finishCallback);
+ }
+
+ @Override
+ public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange,
+ @NonNull final SurfaceControl.Transaction startTransaction,
+ @NonNull final SurfaceControl.Transaction finishTransaction,
+ @NonNull final Transitions.TransitionFinishCallback finishCallback) {
+ if (mFinishCallback != null) {
+ callFinishCallback(null /* wct */);
+ mFinishTransaction = null;
+ throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ }
+
+ // Keep track of the PIP task and animation.
+ mCurrentPipTaskToken = pipChange.getContainer();
+ mHasFadeOut = false;
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
mFinishTransaction = finishTransaction;
- final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation();
- return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
- startTransaction, finishTransaction, enterPip.getStartRotation(),
- endRotation);
- }
- private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final SurfaceControl.Transaction startTransaction,
- final SurfaceControl.Transaction finishTransaction,
- final int startRotation, final int endRotation) {
+ final ActivityManager.RunningTaskInfo taskInfo = pipChange.getTaskInfo();
+ final SurfaceControl leash = pipChange.getLeash();
+ final int startRotation = pipChange.getStartRotation();
+ final int endRotation = mInFixedRotation ? mEndFixedRotation : pipChange.getEndRotation();
+
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -657,7 +696,6 @@ public class PipTransition extends PipTransitionController {
computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
destinationBounds, sourceHintRect);
}
- PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
@@ -694,7 +732,7 @@ public class PipTransition extends PipTransitionController {
null /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
- return true;
+ return;
}
if (rotationDelta != Surface.ROTATION_0) {
@@ -702,6 +740,12 @@ public class PipTransition extends PipTransitionController {
tmpTransform.postRotate(rotationDelta);
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ startTransaction.setAlpha(leash, 0f);
+ }
+ startTransaction.apply();
+
+ PipAnimationController.PipTransitionAnimator animator;
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
@@ -712,7 +756,6 @@ public class PipTransition extends PipTransitionController {
animator.setColorContentOverlay(mContext);
}
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- startTransaction.setAlpha(leash, 0f);
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
0f, 1f);
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -720,7 +763,6 @@ public class PipTransition extends PipTransitionController {
throw new RuntimeException("Unrecognized animation type: "
+ mOneShotAnimationType);
}
- startTransaction.apply();
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration);
@@ -731,8 +773,6 @@ public class PipTransition extends PipTransitionController {
animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
}
animator.start();
-
- return true;
}
/** Computes destination bounds in old rotation and updates source hint rect if available. */
@@ -852,27 +892,4 @@ public class PipTransition extends PipTransitionController {
mPipMenuController.movePipMenu(null, null, destinationBounds);
mPipMenuController.updateMenuBounds(destinationBounds);
}
-
- private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds,
- @PipAnimationController.TransitionDirection int direction,
- WindowContainerTransaction wct) {
- Rect taskBounds = null;
- if (isInPipDirection(direction)) {
- // If we are animating from fullscreen using a bounds animation, then reset the
- // activity windowing mode set by WM, and set the task bounds to the final bounds
- taskBounds = destinationBounds;
- wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
- wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds);
- } else if (isOutPipDirection(direction)) {
- // If we are animating to fullscreen, then we need to reset the override bounds
- // on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP)
- ? null : destinationBounds;
- wct.setWindowingMode(taskInfo.token, getOutPipWindowingMode());
- // Simply reset the activity mode set prior to the animation running.
- wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
- }
-
- wct.setBounds(taskInfo.token, taskBounds);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 54f46e0c9938..d3f69f6762f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.WindowManager.TRANSIT_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
@@ -28,10 +29,16 @@ import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import androidx.annotation.NonNull;
+
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.transition.Transitions;
@@ -206,6 +213,30 @@ public abstract class PipTransitionController implements Transitions.TransitionH
return false;
}
+ /** @return whether the transition-request represents a pip-entry. */
+ public boolean requestHasPipEnter(@NonNull TransitionRequestInfo request) {
+ return request.getType() == TRANSIT_PIP;
+ }
+
+ /** Whether a particular change is a window that is entering pip. */
+ public boolean isEnteringPip(@NonNull TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ return false;
+ }
+
+ /** Add PiP-related changes to `outWCT` for the given request. */
+ public void augmentRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
+ throw new IllegalStateException("Request isn't entering PiP");
+ }
+
+ /** Play a transition animation for entering PiP on a specific PiP change. */
+ public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange,
+ @NonNull final SurfaceControl.Transaction startTransaction,
+ @NonNull final SurfaceControl.Transaction finishTransaction,
+ @NonNull final Transitions.TransitionFinishCallback finishCallback) {
+ }
+
/**
* Callback interface for PiP transitions (both from and to PiP mode)
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index dad261ad9580..c3e6d82df781 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -110,7 +110,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private PipAppOpsListener mAppOpsListener;
private PipMediaController mMediaController;
private PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
private PipBoundsState mPipBoundsState;
+ private PipMotionHelper mPipMotionHelper;
private PipTouchHandler mTouchHandler;
private PipTransitionController mPipTransitionController;
private TaskStackListenerImpl mTaskStackListener;
@@ -156,7 +158,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
* Handler for display rotation changes.
*/
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
- int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+ displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
if (mPipTransitionController.handleRotateDisplay(fromRotation, toRotation, t)) {
return;
}
@@ -286,7 +288,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
@Nullable
public static Pip create(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -301,7 +304,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
- pipBoundsState, pipMediaController,
+ pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
oneHandedController, mainExecutor)
@@ -312,7 +315,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
DisplayController displayController,
PipAppOpsListener pipAppOpsListener,
PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm,
@NonNull PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController,
PipTaskOrganizer pipTaskOrganizer,
@@ -335,7 +340,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
mPipBoundsState = pipBoundsState;
+ mPipMotionHelper = pipMotionHelper;
mPipTaskOrganizer = pipTaskOrganizer;
mMainExecutor = mainExecutor;
mMediaController = pipMediaController;
@@ -542,24 +549,44 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mMenuController.attachPipMenuView();
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
- final Rect postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
- final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeStackBounds,
- mPipBoundsAlgorithm.getMovementBounds(postChangeStackBounds),
+ final Rect postChangeBounds = new Rect(mPipBoundsState.getBounds());
+ final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeBounds,
+ mPipBoundsAlgorithm.getMovementBounds(postChangeBounds),
mPipBoundsState.getStashedState());
+ // Scale PiP on density dpi change, so it appears to be the same size physically.
+ final boolean densityDpiChanged = mPipBoundsState.getDisplayLayout().densityDpi() != 0
+ && (mPipBoundsState.getDisplayLayout().densityDpi() != layout.densityDpi());
+ if (densityDpiChanged) {
+ final float scale = (float) layout.densityDpi()
+ / mPipBoundsState.getDisplayLayout().densityDpi();
+ postChangeBounds.set(0, 0,
+ (int) (postChangeBounds.width() * scale),
+ (int) (postChangeBounds.height() * scale));
+ }
+
updateDisplayLayout.run();
- // Calculate the stack bounds in the new orientation based on same fraction along the
+ // Calculate the PiP bounds in the new orientation based on same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds(
- postChangeStackBounds, false /* adjustForIme */);
- pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+ postChangeBounds, false /* adjustForIme */);
+ pipSnapAlgorithm.applySnapFraction(postChangeBounds, postChangeMovementBounds,
snapFraction, mPipBoundsState.getStashedState(),
mPipBoundsState.getStashOffset(),
mPipBoundsState.getDisplayBounds(),
mPipBoundsState.getDisplayLayout().stableInsets());
- mTouchHandler.getMotionHelper().movePip(postChangeStackBounds);
+ if (densityDpiChanged) {
+ // Using PipMotionHelper#movePip directly here may cause race condition since
+ // the app content in PiP mode may or may not be updated for the new density dpi.
+ final int duration = mContext.getResources().getInteger(
+ R.integer.config_pipEnterAnimationDuration);
+ mPipTaskOrganizer.scheduleAnimateResizePip(
+ postChangeBounds, duration, null /* updateBoundsCallback */);
+ } else {
+ mTouchHandler.getMotionHelper().movePip(postChangeBounds);
+ }
} else {
updateDisplayLayout.run();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
new file mode 100644
index 000000000000..78084fafe197
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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.pip.phone;
+
+import android.graphics.Rect;
+import android.util.ArraySet;
+
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+
+import java.util.Set;
+
+/**
+ * Calculates the adjusted position that does not occlude keep clear areas.
+ */
+public class PipKeepClearAlgorithm {
+
+ /**
+ * Adjusts the current position of PiP to avoid occluding keep clear areas. If the user has
+ * moved PiP manually, the unmodified current position will be returned instead.
+ */
+ public Rect adjust(PipBoundsState boundsState, PipBoundsAlgorithm boundsAlgorithm) {
+ if (boundsState.hasUserResizedPip()) {
+ return boundsState.getBounds();
+ }
+ return adjust(boundsAlgorithm.getEntryDestinationBounds(),
+ boundsState.getRestrictedKeepClearAreas(),
+ boundsState.getUnrestrictedKeepClearAreas(), boundsState.getDisplayBounds());
+ }
+
+ /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
+ public Rect adjust(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+ Set<Rect> unrestrictedKeepClearAreas, Rect displayBounds) {
+ if (restrictedKeepClearAreas.isEmpty()) {
+ return defaultBounds;
+ }
+ Set<Rect> keepClearAreas = new ArraySet<>();
+ if (!restrictedKeepClearAreas.isEmpty()) {
+ keepClearAreas.addAll(restrictedKeepClearAreas);
+ }
+ Rect outBounds = new Rect(defaultBounds);
+ for (Rect r : keepClearAreas) {
+ if (Rect.intersects(r, outBounds)) {
+ if (tryOffsetUp(outBounds, r, displayBounds)) continue;
+ if (tryOffsetLeft(outBounds, r, displayBounds)) continue;
+ if (tryOffsetDown(outBounds, r, displayBounds)) continue;
+ if (tryOffsetRight(outBounds, r, displayBounds)) continue;
+ }
+ }
+ return outBounds;
+ }
+
+ private boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ rectToAvoid.left - rectToMove.right, 0);
+ }
+
+ private boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ rectToAvoid.right - rectToMove.left, 0);
+ }
+
+ private boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ 0, rectToAvoid.top - rectToMove.bottom);
+ }
+
+ private boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ 0, rectToAvoid.bottom - rectToMove.top);
+ }
+
+ private boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect displayBounds,
+ int dx, int dy) {
+ Rect tmp = new Rect(rectToMove);
+ tmp.offset(dx, dy);
+ if (!Rect.intersects(rectToAvoid, tmp) && displayBounds.contains(tmp)) {
+ rectToMove.offsetTo(tmp.left, tmp.top);
+ return true;
+ }
+ return false;
+ }
+}
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 6390c8984dac..1958157fc319 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
@@ -282,7 +282,7 @@ public class PipMenuView extends FrameLayout {
&& mSplitScreenControllerOptional.get().isTaskInSplitScreen(taskInfo.taskId);
mFocusedTaskAllowSplitScreen = isSplitScreen
|| (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && taskInfo.supportsSplitScreenMultiWindow
+ && taskInfo.supportsMultiWindow
&& taskInfo.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME);
}
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 ac7b9033b2b9..a2ff97247189 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
@@ -54,6 +54,7 @@ import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -250,6 +251,10 @@ public class PipTouchHandler {
});
}
+ public PipTransitionController getTransitionHandler() {
+ return mPipTaskOrganizer.getTransitionController();
+ }
+
private void reloadResources() {
final Resources res = mContext.getResources();
mBottomOffsetBufferPx = res.getDimensionPixelSize(R.dimen.pip_bottom_offset_buffer);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl
index 6e78fcba4a00..b71cc32a0347 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl
@@ -16,6 +16,8 @@
package com.android.wm.shell.recents;
+import android.app.ActivityManager;
+
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -38,4 +40,9 @@ interface IRecentTasks {
* Gets the set of recent tasks.
*/
GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId) = 3;
+
+ /**
+ * Gets the set of running tasks.
+ */
+ ActivityManager.RunningTaskInfo[] getRunningTasks(int maxNum) = 4;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
index 8efa42830d80..59f72335678e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -16,6 +16,8 @@
package com.android.wm.shell.recents;
+import android.app.ActivityManager;
+
/**
* Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
*/
@@ -25,4 +27,14 @@ oneway interface IRecentTasksListener {
* Called when the set of recent tasks change.
*/
void onRecentTasksChanged();
+
+ /**
+ * Called when a running task appears.
+ */
+ void onRunningTaskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
+
+ /**
+ * Called when a running task vanishes.
+ */
+ void onRunningTaskVanished(in ActivityManager.RunningTaskInfo taskInfo);
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index c166178e9bbd..d903d5b33780 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.recents;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.content.pm.PackageManager.FEATURE_PC;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
@@ -63,8 +64,9 @@ public class RecentTasksController implements TaskStackListenerCallback,
private final ShellExecutor mMainExecutor;
private final TaskStackListenerImpl mTaskStackListener;
private final RecentTasks mImpl = new RecentTasksImpl();
+ private IRecentTasksListener mListener;
+ private final boolean mIsDesktopMode;
- private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
// Mapping of split task ids, mappings are symmetrical (ie. if t1 is the taskid of a task in a
// pair, then mSplitTasks[t1] = t2, and mSplitTasks[t2] = t1)
private final SparseIntArray mSplitTasks = new SparseIntArray();
@@ -95,6 +97,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
RecentTasksController(Context context, TaskStackListenerImpl taskStackListener,
ShellExecutor mainExecutor) {
mContext = context;
+ mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mTaskStackListener = taskStackListener;
mMainExecutor = mainExecutor;
}
@@ -176,10 +179,15 @@ public class RecentTasksController implements TaskStackListenerCallback,
notifyRecentTasksChanged();
}
- public void onTaskRemoved(TaskInfo taskInfo) {
+ public void onTaskAdded(ActivityManager.RunningTaskInfo taskInfo) {
+ notifyRunningTaskAppeared(taskInfo);
+ }
+
+ public void onTaskRemoved(ActivityManager.RunningTaskInfo taskInfo) {
// Remove any split pairs associated with this task
removeSplitPair(taskInfo.taskId);
notifyRecentTasksChanged();
+ notifyRunningTaskVanished(taskInfo);
}
public void onTaskWindowingModeChanged(TaskInfo taskInfo) {
@@ -189,19 +197,50 @@ public class RecentTasksController implements TaskStackListenerCallback,
@VisibleForTesting
void notifyRecentTasksChanged() {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).run();
+ if (mListener == null) {
+ return;
+ }
+ try {
+ mListener.onRecentTasksChanged();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call notifyRecentTasksChanged", e);
}
}
- private void registerRecentTasksListener(Runnable listener) {
- if (!mCallbacks.contains(listener)) {
- mCallbacks.add(listener);
+ /**
+ * Notify the running task listener that a task appeared on desktop environment.
+ */
+ private void notifyRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mListener == null || !mIsDesktopMode || taskInfo.realActivity == null) {
+ return;
+ }
+ try {
+ mListener.onRunningTaskAppeared(taskInfo);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call onRunningTaskAppeared", e);
+ }
+ }
+
+ /**
+ * Notify the running task listener that a task was removed on desktop environment.
+ */
+ private void notifyRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mListener == null || !mIsDesktopMode || taskInfo.realActivity == null) {
+ return;
+ }
+ try {
+ mListener.onRunningTaskVanished(taskInfo);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call onRunningTaskVanished", e);
}
}
- private void unregisterRecentTasksListener(Runnable listener) {
- mCallbacks.remove(listener);
+ private void registerRecentTasksListener(IRecentTasksListener listener) {
+ mListener = listener;
+ }
+
+ private void unregisterRecentTasksListener() {
+ mListener = null;
}
@VisibleForTesting
@@ -280,19 +319,28 @@ public class RecentTasksController implements TaskStackListenerCallback,
private RecentTasksController mController;
private final SingleInstanceRemoteListener<RecentTasksController,
IRecentTasksListener> mListener;
- private final Runnable mRecentTasksListener =
- new Runnable() {
- @Override
- public void run() {
- mListener.call(l -> l.onRecentTasksChanged());
- }
- };
+ private final IRecentTasksListener mRecentTasksListener = new IRecentTasksListener.Stub() {
+ @Override
+ public void onRecentTasksChanged() throws RemoteException {
+ mListener.call(l -> l.onRecentTasksChanged());
+ }
+
+ @Override
+ public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+ mListener.call(l -> l.onRunningTaskAppeared(taskInfo));
+ }
+
+ @Override
+ public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ mListener.call(l -> l.onRunningTaskVanished(taskInfo));
+ }
+ };
public IRecentTasksImpl(RecentTasksController controller) {
mController = controller;
mListener = new SingleInstanceRemoteListener<>(controller,
c -> c.registerRecentTasksListener(mRecentTasksListener),
- c -> c.unregisterRecentTasksListener(mRecentTasksListener));
+ c -> c.unregisterRecentTasksListener());
}
/**
@@ -331,5 +379,16 @@ public class RecentTasksController implements TaskStackListenerCallback,
true /* blocking */);
return out[0];
}
+
+ @Override
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(int maxNum) {
+ final ActivityManager.RunningTaskInfo[][] tasks =
+ new ActivityManager.RunningTaskInfo[][] {null};
+ executeRemoteCallWithTaskPermission(mController, "getRunningTasks",
+ (controller) -> tasks[0] = ActivityTaskManager.getInstance().getTasks(maxNum)
+ .toArray(new ActivityManager.RunningTaskInfo[0]),
+ true /* blocking */);
+ return tasks[0];
+ }
}
} \ No newline at end of file
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 31b510c38457..0d976d4a81eb 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
@@ -108,7 +108,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
static final int EXIT_REASON_ROOT_TASK_VANISHED = 6;
static final int EXIT_REASON_SCREEN_LOCKED = 7;
static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
- static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
+ public static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
@IntDef(value = {
EXIT_REASON_UNKNOWN,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -198,6 +198,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return mStageCoordinator.isSplitScreenVisible();
}
+ public StageCoordinator getTransitionHandler() {
+ return mStageCoordinator;
+ }
+
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
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 cd121ed41fdd..f7057d454df9 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
@@ -21,7 +21,6 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
@@ -58,9 +57,6 @@ import java.util.ArrayList;
class SplitScreenTransitions {
private static final String TAG = "SplitScreenTransitions";
- /** Flag applied to a transition change to identify it as a divider bar for animation. */
- public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
-
private final TransactionPool mTransactionPool;
private final Transitions mTransitions;
private final Runnable mOnFinish;
@@ -70,8 +66,9 @@ class SplitScreenTransitions {
IBinder mPendingRecent = null;
private IBinder mAnimatingTransition = null;
- private OneShotRemoteHandler mPendingRemoteHandler = null;
+ OneShotRemoteHandler mPendingRemoteHandler = null;
private OneShotRemoteHandler mActiveRemoteHandler = null;
+ private boolean mEnterTransitionMerged;
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
@@ -94,7 +91,8 @@ class SplitScreenTransitions {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
- @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot) {
+ @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
+ @NonNull WindowContainerToken topRoot) {
mFinishCallback = finishCallback;
mAnimatingTransition = transition;
if (mPendingRemoteHandler != null) {
@@ -104,12 +102,12 @@ class SplitScreenTransitions {
mPendingRemoteHandler = null;
return;
}
- playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot);
+ playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot, topRoot);
}
private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
- @NonNull WindowContainerToken sideRoot) {
+ @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
mFinishTransaction = mTransactionPool.acquire();
// Play some place-holder fade animations
@@ -140,7 +138,10 @@ class SplitScreenTransitions {
endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
startExampleResizeAnimation(leash, startBounds, endBounds);
}
- if (change.getParent() != null) {
+ boolean isRootOrSplitSideRoot = change.getParent() == null
+ || topRoot.equals(change.getParent());
+ // For enter or exit, we only want to animate the side roots but not the top-root.
+ if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer())) {
continue;
}
@@ -187,27 +188,28 @@ class SplitScreenTransitions {
}
/** Starts a transition to dismiss split. */
- IBinder startDismissTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
+ IBinder startDismissTransition(WindowContainerTransaction wct,
Transitions.TransitionHandler handler, @SplitScreen.StageType int dismissTop,
@SplitScreenController.ExitReason int reason) {
final int type = reason == EXIT_REASON_DRAG_DIVIDER
? TRANSIT_SPLIT_DISMISS_SNAP : TRANSIT_SPLIT_DISMISS;
- if (transition == null) {
- transition = mTransitions.startTransition(type, wct, handler);
- }
+ IBinder transition = mTransitions.startTransition(type, wct, handler);
+ setDismissTransition(transition, dismissTop, reason);
+ return transition;
+ }
+
+ /** Sets a transition to dismiss split. */
+ void setDismissTransition(@NonNull IBinder transition, @SplitScreen.StageType int dismissTop,
+ @SplitScreenController.ExitReason int reason) {
mPendingDismiss = new DismissTransition(transition, reason, dismissTop);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Dismiss due to %s. toTop=%s",
exitReasonToString(reason), stageTypeToString(dismissTop));
- return transition;
}
- IBinder startRecentTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
- Transitions.TransitionHandler handler, @Nullable RemoteTransition remoteTransition) {
- if (transition == null) {
- transition = mTransitions.startTransition(TRANSIT_OPEN, wct, handler);
- }
+ void setRecentTransition(@NonNull IBinder transition,
+ @Nullable RemoteTransition remoteTransition) {
mPendingRecent = transition;
if (remoteTransition != null) {
@@ -219,7 +221,6 @@ class SplitScreenTransitions {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Enter recent panel");
- return transition;
}
void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
@@ -229,6 +230,18 @@ class SplitScreenTransitions {
}
}
+ void onTransitionMerged(@NonNull IBinder transition) {
+ // Once a pending enter transition got merged, make sure to append the reset of finishing
+ // operations to the finish transition.
+ if (transition == mPendingEnter) {
+ mFinishTransaction = mTransactionPool.acquire();
+ mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
+ mPendingEnter = null;
+ mPendingRemoteHandler = null;
+ mEnterTransitionMerged = true;
+ }
+ }
+
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return;
if (mAnimatingTransition == mPendingEnter) {
@@ -238,18 +251,16 @@ class SplitScreenTransitions {
mPendingDismiss = null;
}
if (mAnimatingTransition == mPendingRecent) {
- // If the clean-up wct is null when finishing recent transition, it indicates it's
- // returning to home and thus no need to reorder tasks.
- final boolean returnToHome = wct == null;
- if (returnToHome) {
- wct = new WindowContainerTransaction();
+ if (!mEnterTransitionMerged) {
+ if (wct == null) wct = new WindowContainerTransaction();
+ mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
}
- mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction);
mPendingRecent = null;
}
mPendingRemoteHandler = null;
mActiveRemoteHandler = null;
mAnimatingTransition = null;
+ mEnterTransitionMerged = false;
mOnFinish.run();
if (mFinishTransaction != null) {
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 7ea32a6d8f86..f625387a05d5 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
@@ -28,7 +28,9 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -47,7 +49,6 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
-import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -83,6 +84,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
+import android.window.DisplayAreaInfo;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -131,12 +133,15 @@ import javax.inject.Provider;
* This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
* {@link #onStageHasChildrenChanged(StageListenerImpl).}
*/
-class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
ShellTaskOrganizer.TaskListener {
private static final String TAG = StageCoordinator.class.getSimpleName();
+ /** Flag applied to a transition change to identify it as a divider bar for animation. */
+ public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
+
private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final MainStage mMainStage;
@@ -365,10 +370,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition, wct);
+ if (mMainStage.isActive()) {
+ mMainStage.evictAllChildren(wct);
+ mSideStage.evictAllChildren(wct);
+ } else {
+ // Build a request WCT that will launch both apps such that task 0 is on the main stage
+ // while task 1 is on the side stage.
+ mMainStage.activate(wct, false /* reparent */);
+ }
mSplitLayout.setDivideRatio(splitRatio);
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(wct, false /* reparent */);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
@@ -641,7 +651,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+ mSplitTransitions.startDismissTransition(wct, this,
mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
} else {
exitSplitScreen(
@@ -674,8 +684,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
- dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ mSplitTransitions.startDismissTransition(wct, this, dismissTop,
+ EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
}
}
@@ -738,10 +748,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setDividerVisibility(false, t);
});
- // Hide divider and reset its position.
- mSplitLayout.resetDividerPosition();
- mSplitLayout.release();
- mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ onTransitionAnimationComplete();
Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason));
// Log the exit
if (childrenToTop != null) {
@@ -1024,8 +1031,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
// Make the stages adjacent to each other so they occlude what's behind them.
- wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
- true /* moveTogether */);
+ wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
mTaskOrganizer.applyTransaction(wct);
}
@@ -1202,8 +1208,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(
- null /* transition */, wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
+ if (mRootTaskInfo != null) {
+ wct.setDoNotPip(mRootTaskInfo.token);
+ }
+ mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
}
@Override
@@ -1321,7 +1329,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (displayId != DEFAULT_DISPLAY) {
return;
}
- mDisplayController.addDisplayChangingController(this::onRotateDisplay);
+ mDisplayController.addDisplayChangingController(this::onDisplayChange);
}
@Override
@@ -1332,14 +1340,17 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
}
- private void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- WindowContainerTransaction wct) {
+ private void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
if (!mMainStage.isActive()) return;
// Only do this when shell transition
if (!ENABLE_SHELL_TRANSITIONS) return;
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
+ if (newDisplayAreaInfo != null) {
+ mSplitLayout.updateConfiguration(newDisplayAreaInfo.configuration);
+ }
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
}
@@ -1392,7 +1403,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Nullable TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
- if (mMainStage.isActive()) {
+ if (isSplitActive()) {
+ // Check if the display is rotating.
final TransitionRequestInfo.DisplayChange displayChange =
request.getDisplayChange();
if (request.getType() == TRANSIT_CHANGE && displayChange != null
@@ -1419,7 +1431,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mRecentTasks.ifPresent(recentTasks -> recentTasks.removeSplitPair(triggerTask.taskId));
}
- if (mMainStage.isActive()) {
+ if (isSplitActive()) {
// Try to handle everything while in split-screen, so return a WCT even if it's empty.
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " split is active so using split"
+ "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
@@ -1434,7 +1446,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_SIDE
: STAGE_TYPE_MAIN;
prepareExitSplitScreen(dismissTop, out);
- mSplitTransitions.startDismissTransition(transition, out, this, dismissTop,
+ mSplitTransitions.setDismissTransition(transition, dismissTop,
EXIT_REASON_APP_FINISHED);
}
} else if (isOpening && inFullscreen) {
@@ -1444,12 +1456,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} else if (activityType == ACTIVITY_TYPE_HOME
|| activityType == ACTIVITY_TYPE_RECENTS) {
// Enter overview panel, so start recent transition.
- mSplitTransitions.startRecentTransition(transition, out, this,
+ mSplitTransitions.setRecentTransition(transition,
request.getRemoteTransition());
- } else {
- // Occluded by the other fullscreen task, so dismiss both.
+ } else if (mSplitTransitions.mPendingRecent == null) {
+ // If split-task is not controlled by recents animation
+ // and occluded by the other fullscreen task, dismiss both.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
- mSplitTransitions.startDismissTransition(transition, out, this,
+ mSplitTransitions.setDismissTransition(transition,
STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
}
}
@@ -1464,6 +1477,33 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return out;
}
+ /**
+ * This is used for mixed scenarios. For such scenarios, just make sure to include exiting
+ * split or entering split when appropriate.
+ */
+ public void addEnterOrExitIfNeeded(@Nullable TransitionRequestInfo request,
+ @NonNull WindowContainerTransaction outWCT) {
+ final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
+ if (triggerTask != null && triggerTask.displayId != mDisplayId) {
+ // Skip handling task on the other display.
+ return;
+ }
+ final @WindowManager.TransitionType int type = request.getType();
+ if (isSplitActive() && !isOpeningType(type)
+ && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " One of the splits became "
+ + "empty during a mixed transition (one not handled by split),"
+ + " so make sure split-screen state is cleaned-up. "
+ + "mainStageCount=%d sideStageCount=%d", mMainStage.getChildCount(),
+ mSideStage.getChildCount());
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, outWCT);
+ }
+ }
+
+ public boolean isSplitActive() {
+ return mMainStage.isActive();
+ }
+
@Override
public void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
@@ -1473,15 +1513,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onTransitionMerged(@NonNull IBinder transition) {
- // Once the pending enter transition got merged, make sure to bring divider bar visible and
- // clear the pending transition from cache to prevent mess-up the following state.
- if (transition == mSplitTransitions.mPendingEnter) {
- final SurfaceControl.Transaction t = mTransactionPool.acquire();
- finishEnterSplitScreen(t);
- mSplitTransitions.mPendingEnter = null;
- t.apply();
- mTransactionPool.release(t);
- }
+ mSplitTransitions.onTransitionMerged(transition);
}
@Override
@@ -1552,11 +1584,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!shouldAnimate) return false;
mSplitTransitions.playAnimation(transition, info, startTransaction, finishTransaction,
- finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+ finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
+ mRootTaskInfo.token);
return true;
}
- void onTransitionAnimationComplete() {
+ /** Called to clean-up state and do house-keeping after the animation is done. */
+ public void onTransitionAnimationComplete() {
// If still playing, let it finish.
if (!mMainStage.isActive()) {
// Update divider state after animation so that it is still around and positioned
@@ -1620,8 +1654,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return true;
}
- private boolean startPendingDismissAnimation(
- @NonNull SplitScreenTransitions.DismissTransition dismissTransition,
+ /** Synchronize split-screen state with transition and make appropriate preparations. */
+ public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
@NonNull SurfaceControl.Transaction finishT) {
// Make some noise if things aren't totally expected. These states shouldn't effect
@@ -1654,7 +1688,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
- if (shouldBreakPairedTaskInRecents(dismissTransition.mReason) && mShouldUpdateRecents) {
+ if (shouldBreakPairedTaskInRecents(dismissReason) && mShouldUpdateRecents) {
for (TransitionInfo.Change change : info.getChanges()) {
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo != null
@@ -1671,30 +1705,37 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Wait until after animation to update divider
// Reset crops so they don't interfere with subsequent launches
- t.setWindowCrop(mMainStage.mRootLeash, null);
- t.setWindowCrop(mSideStage.mRootLeash, null);
+ t.setCrop(mMainStage.mRootLeash, null);
+ t.setCrop(mSideStage.mRootLeash, null);
+
+ if (toStage == STAGE_TYPE_UNDEFINED) {
+ logExit(dismissReason);
+ } else {
+ logExitToStage(dismissReason, toStage == STAGE_TYPE_MAIN);
+ }
+ // Hide divider and dim layer on transition finished.
+ setDividerVisibility(false, finishT);
+ finishT.hide(mMainStage.mDimLayer);
+ finishT.hide(mSideStage.mDimLayer);
+ }
+
+ private boolean startPendingDismissAnimation(
+ @NonNull SplitScreenTransitions.DismissTransition dismissTransition,
+ @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.Transaction finishT) {
+ prepareDismissAnimation(dismissTransition.mDismissTop, dismissTransition.mReason, info,
+ t, finishT);
if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
- logExit(dismissTransition.mReason);
// TODO: Have a proper remote for this. Until then, though, reset state and use the
// normal animation stuff (which falls back to the normal launcher remote).
+ t.hide(mSplitLayout.getDividerLeash());
mSplitLayout.release(t);
mSplitTransitions.mPendingDismiss = null;
return false;
- } else {
- logExitToStage(dismissTransition.mReason,
- dismissTransition.mDismissTop == STAGE_TYPE_MAIN);
}
addDividerBarToTransition(info, t, false /* show */);
- // We're dismissing split by moving the other one to fullscreen.
- // Since we don't have any animations for this yet, just use the internal example
- // animations.
-
- // Hide divider and dim layer on transition finished.
- setDividerVisibility(false, finishT);
- finishT.hide(mMainStage.mDimLayer);
- finishT.hide(mSideStage.mDimLayer);
return true;
}
@@ -1704,26 +1745,26 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return true;
}
- void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct,
+ void onRecentTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction finishT) {
- // Exclude the case that the split screen has been dismissed already.
- if (!mMainStage.isActive()) {
- // The latest split dismissing transition might be a no-op transition and thus won't
- // callback startAnimation, update split visibility here to cover this kind of no-op
- // transition case.
- setSplitsVisible(false);
- return;
+ // Check if the recent transition is finished by returning to the current split so we can
+ // restore the divider bar.
+ for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
+ final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
+ final IBinder container = op.getContainer();
+ if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
+ && (mMainStage.containsContainer(container)
+ || mSideStage.containsContainer(container))) {
+ setDividerVisibility(true, finishT);
+ return;
+ }
}
- if (returnToHome) {
- // When returning to home from recent apps, the splitting tasks are already hidden, so
- // append the reset of dismissing operations into the clean-up wct.
- prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
- setSplitsVisible(false);
- logExit(EXIT_REASON_RETURN_HOME);
- } else {
- setDividerVisibility(true, finishT);
- }
+ // Dismiss the split screen is it's not returning to split.
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+ setSplitsVisible(false);
+ setDividerVisibility(false, finishT);
+ logExit(EXIT_REASON_UNKNOWN);
}
private void addDividerBarToTransition(@NonNull TransitionInfo info,
@@ -1870,8 +1911,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(stageType, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct,
- StageCoordinator.this, stageType,
+ mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
}
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 949bf5f55808..f9dd7c96294f 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
@@ -31,6 +31,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -47,6 +48,7 @@ import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Base class that handle common task org. related for split-screen stages.
@@ -119,63 +121,53 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
boolean containsToken(WindowContainerToken token) {
- if (token.equals(mRootTaskInfo.token)) {
- return true;
- }
-
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- if (token.equals(mChildrenTaskInfo.valueAt(i).token)) {
- return true;
- }
- }
+ return contains(t -> t.token.equals(token));
+ }
- return false;
+ boolean containsContainer(IBinder binder) {
+ return contains(t -> t.token.asBinder() == binder);
}
/**
* Returns the top visible child task's id.
*/
int getTopVisibleChildTaskId() {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
- if (info.isVisible) {
- return info.taskId;
- }
- }
- return INVALID_TASK_ID;
+ final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible);
+ return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
}
/**
* Returns the top activity uid for the top child task.
*/
int getTopChildTaskUid() {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
- if (info.topActivityInfo == null) {
- continue;
- }
- return info.topActivityInfo.applicationInfo.uid;
- }
- return 0;
+ final ActivityManager.RunningTaskInfo taskInfo =
+ getChildTaskInfo(t -> t.topActivityInfo != null);
+ return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0;
}
/** @return {@code true} if this listener contains the currently focused task. */
boolean isFocused() {
- if (mRootTaskInfo == null) {
- return false;
- }
+ return contains(t -> t.isFocused);
+ }
- if (mRootTaskInfo.isFocused) {
+ private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) {
+ if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) {
return true;
}
+ return getChildTaskInfo(predicate) != null;
+ }
+
+ @Nullable
+ private ActivityManager.RunningTaskInfo getChildTaskInfo(
+ Predicate<ActivityManager.RunningTaskInfo> predicate) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- if (mChildrenTaskInfo.valueAt(i).isFocused) {
- return true;
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ if (predicate.test(taskInfo)) {
+ return taskInfo;
}
}
-
- return false;
+ return null;
}
@Override
@@ -266,13 +258,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
- if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
- mCallbacks.onChildTaskEnterPip(taskId);
- }
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
return;
}
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ mCallbacks.onChildTaskEnterPip(taskId);
+ }
sendStatusChanged();
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreen.aidl
deleted file mode 100644
index 45f6d3c8b154..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreen.aidl
+++ /dev/null
@@ -1,103 +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.stagesplit;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.window.RemoteTransition;
-
-import com.android.wm.shell.stagesplit.ISplitScreenListener;
-
-/**
- * Interface that is exposed to remote callers to manipulate the splitscreen feature.
- */
-interface ISplitScreen {
-
- /**
- * Registers a split screen listener.
- */
- oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
-
- /**
- * Unregisters a split screen listener.
- */
- oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
-
- /**
- * Hides the side-stage if it is currently visible.
- */
- oneway void setSideStageVisibility(boolean visible) = 3;
-
- /**
- * Removes a task from the side stage.
- */
- oneway void removeFromSideStage(int taskId) = 4;
-
- /**
- * Removes the split-screen stages and leaving indicated task to top. Passing INVALID_TASK_ID
- * to indicate leaving no top task after leaving split-screen.
- */
- oneway void exitSplitScreen(int toTopTaskId) = 5;
-
- /**
- * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible.
- */
- oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
-
- /**
- * Starts a task in a stage.
- */
- oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7;
-
- /**
- * Starts a shortcut in a stage.
- */
- oneway void startShortcut(String packageName, String shortcutId, int stage, int position,
- in Bundle options, in UserHandle user) = 8;
-
- /**
- * Starts an activity in a stage.
- */
- oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
- int position, in Bundle options) = 9;
-
- /**
- * Starts tasks simultaneously in one transition.
- */
- oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
- in Bundle sideOptions, int sidePosition, in RemoteTransition remoteTransition) = 10;
-
- /**
- * Version of startTasks using legacy transition system.
- */
- oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
- int sideTaskId, in Bundle sideOptions, int sidePosition,
- in RemoteAnimationAdapter adapter) = 11;
-
- /**
- * Blocking call that notifies and gets additional split-screen targets when entering
- * recents (for example: the dividerBar).
- * @param cancel is true if leaving recents back to split (eg. the gesture was cancelled).
- * @param appTargets apps that will be re-parented to display area
- */
- RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
- in RemoteAnimationTarget[] appTargets) = 12;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreenListener.aidl
deleted file mode 100644
index 46e4299f99fa..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreenListener.aidl
+++ /dev/null
@@ -1,33 +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.stagesplit;
-
-/**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
- */
-oneway interface ISplitScreenListener {
-
- /**
- * Called when the stage position changes.
- */
- void onStagePositionChanged(int stage, int position);
-
- /**
- * Called when a task changes stages.
- */
- void onTaskStageChanged(int taskId, int stage, boolean visible);
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/MainStage.java
deleted file mode 100644
index 83855be91e04..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/MainStage.java
+++ /dev/null
@@ -1,104 +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.stagesplit;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-/**
- * Main stage for split-screen mode. When split-screen is active all standard activity types launch
- * on the main stage, except for task that are explicitly pinned to the {@link SideStage}.
- * @see StageCoordinator
- */
-class MainStage extends StageTaskListener {
- private static final String TAG = MainStage.class.getSimpleName();
-
- private boolean mIsActive = false;
-
- MainStage(ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
- @Nullable StageTaskUnfoldController stageTaskUnfoldController) {
- super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- stageTaskUnfoldController);
- }
-
- boolean isActive() {
- return mIsActive;
- }
-
- void activate(Rect rootBounds, WindowContainerTransaction wct) {
- if (mIsActive) return;
-
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setBounds(rootToken, rootBounds)
- .setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW)
- .setLaunchRoot(
- rootToken,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES)
- .reparentTasks(
- null /* currentParent */,
- rootToken,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */)
- // Moving the root task to top after the child tasks were re-parented , or the root
- // task cannot be visible and focused.
- .reorder(rootToken, true /* onTop */);
-
- mIsActive = true;
- }
-
- void deactivate(WindowContainerTransaction wct) {
- deactivate(wct, false /* toTop */);
- }
-
- void deactivate(WindowContainerTransaction wct, boolean toTop) {
- if (!mIsActive) return;
- mIsActive = false;
-
- if (mRootTaskInfo == null) return;
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setLaunchRoot(
- rootToken,
- null,
- null)
- .reparentTasks(
- rootToken,
- null /* newParent */,
- CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
- CONTROLLED_ACTIVITY_TYPES,
- toTop)
- // We want this re-order to the bottom regardless since we are re-parenting
- // all its tasks.
- .reorder(rootToken, false /* onTop */);
- }
-
- void updateConfiguration(int windowingMode, Rect bounds, WindowContainerTransaction wct) {
- wct.setBounds(mRootTaskInfo.token, bounds)
- .setWindowingMode(mRootTaskInfo.token, windowingMode);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
deleted file mode 100644
index 264e88f32bff..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# WM shell sub-modules stagesplit owner
-chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineManager.java
deleted file mode 100644
index 8fbad52c630f..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineManager.java
+++ /dev/null
@@ -1,181 +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.stagesplit;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.view.IWindow;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-import android.widget.FrameLayout;
-
-import com.android.wm.shell.R;
-
-/**
- * Handles drawing outline of the bounds of provided root surface. The outline will be drown with
- * the consideration of display insets like status bar, navigation bar and display cutout.
- */
-class OutlineManager extends WindowlessWindowManager {
- private static final String WINDOW_NAME = "SplitOutlineLayer";
- private final Context mContext;
- private final Rect mRootBounds = new Rect();
- private final Rect mTempRect = new Rect();
- private final Rect mLastOutlineBounds = new Rect();
- private final InsetsState mInsetsState = new InsetsState();
- private final int mExpandedTaskBarHeight;
- private OutlineView mOutlineView;
- private SurfaceControlViewHost mViewHost;
- private SurfaceControl mHostLeash;
- private SurfaceControl mLeash;
-
- OutlineManager(Context context, Configuration configuration) {
- super(configuration, null /* rootSurface */, null /* hostInputToken */);
- mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
- null /* options */);
- mExpandedTaskBarHeight = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.taskbar_frame_height);
- }
-
- @Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- b.setParent(mHostLeash);
- }
-
- void inflate(SurfaceControl rootLeash, Rect rootBounds) {
- if (mLeash != null || mViewHost != null) return;
-
- mHostLeash = rootLeash;
- mRootBounds.set(rootBounds);
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
-
- final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(mContext)
- .inflate(R.layout.split_outline, null);
- mOutlineView = rootLayout.findViewById(R.id.split_outline);
-
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
- lp.width = mRootBounds.width();
- lp.height = mRootBounds.height();
- lp.token = new Binder();
- lp.setTitle(WINDOW_NAME);
- lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
- // TRUSTED_OVERLAY for windowless window without input channel.
- mViewHost.setView(rootLayout, lp);
- mLeash = getSurfaceControl(mViewHost.getWindowToken());
-
- drawOutline();
- }
-
- void release() {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
- mRootBounds.setEmpty();
- mLastOutlineBounds.setEmpty();
- mOutlineView = null;
- mHostLeash = null;
- mLeash = null;
- }
-
- @Nullable
- SurfaceControl getOutlineLeash() {
- return mLeash;
- }
-
- void setVisibility(boolean visible) {
- if (mOutlineView != null) {
- mOutlineView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- void setRootBounds(Rect rootBounds) {
- if (mViewHost == null || mViewHost.getView() == null) {
- return;
- }
-
- if (!mRootBounds.equals(rootBounds)) {
- WindowManager.LayoutParams lp =
- (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
- lp.width = rootBounds.width();
- lp.height = rootBounds.height();
- mViewHost.relayout(lp);
- mRootBounds.set(rootBounds);
- drawOutline();
- }
- }
-
- void onInsetsChanged(InsetsState insetsState) {
- if (!mInsetsState.equals(insetsState)) {
- mInsetsState.set(insetsState);
- drawOutline();
- }
- }
-
- private void computeOutlineBounds(Rect rootBounds, InsetsState insetsState, Rect outBounds) {
- outBounds.set(rootBounds);
- 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) {
- outBounds.inset(taskBarInsetsSource.calculateVisibleInsets(outBounds));
- }
-
- // Offset the coordinate from screen based to surface based.
- outBounds.offset(-rootBounds.left, -rootBounds.top);
- }
-
- void drawOutline() {
- if (mOutlineView == null) {
- return;
- }
-
- computeOutlineBounds(mRootBounds, mInsetsState, mTempRect);
- if (mTempRect.equals(mLastOutlineBounds)) {
- return;
- }
-
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mOutlineView.getLayoutParams();
- lp.leftMargin = mTempRect.left;
- lp.topMargin = mTempRect.top;
- lp.width = mTempRect.width();
- lp.height = mTempRect.height();
- mOutlineView.setLayoutParams(lp);
- mLastOutlineBounds.set(mTempRect);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineView.java
deleted file mode 100644
index 92b1381fc808..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineView.java
+++ /dev/null
@@ -1,82 +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.stagesplit;
-
-import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
-import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
-import static android.view.RoundedCorner.POSITION_TOP_LEFT;
-import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.util.AttributeSet;
-import android.view.RoundedCorner;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.R;
-
-/** View for drawing split outline. */
-public class OutlineView extends View {
- private final Paint mPaint = new Paint();
- private final Path mPath = new Path();
- private final float[] mRadii = new float[8];
-
- public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeWidth(
- getResources().getDimension(R.dimen.accessibility_focus_highlight_stroke_width));
- mPaint.setColor(getResources().getColor(R.color.system_accent1_100, null));
- }
-
- @Override
- protected void onAttachedToWindow() {
- // TODO(b/200850654): match the screen corners with the actual display decor.
- mRadii[0] = mRadii[1] = getCornerRadius(POSITION_TOP_LEFT);
- mRadii[2] = mRadii[3] = getCornerRadius(POSITION_TOP_RIGHT);
- mRadii[4] = mRadii[5] = getCornerRadius(POSITION_BOTTOM_RIGHT);
- mRadii[6] = mRadii[7] = getCornerRadius(POSITION_BOTTOM_LEFT);
- }
-
- private int getCornerRadius(@RoundedCorner.Position int position) {
- final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(position);
- return roundedCorner == null ? 0 : roundedCorner.getRadius();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (changed) {
- mPath.reset();
- mPath.addRoundRect(0, 0, getWidth(), getHeight(), mRadii, Path.Direction.CW);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawPath(mPath, mPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SideStage.java
deleted file mode 100644
index 55c4f3aea19a..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SideStage.java
+++ /dev/null
@@ -1,144 +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.stagesplit;
-
-import android.annotation.CallSuper;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.graphics.Rect;
-import android.view.InsetsSourceControl;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-/**
- * Side stage for split-screen mode. Only tasks that are explicitly pinned to this stage show up
- * here. All other task are launch in the {@link MainStage}.
- *
- * @see StageCoordinator
- */
-class SideStage extends StageTaskListener implements
- DisplayInsetsController.OnInsetsChangedListener {
- private static final String TAG = SideStage.class.getSimpleName();
- private final Context mContext;
- private OutlineManager mOutlineManager;
-
- SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
- @Nullable StageTaskUnfoldController stageTaskUnfoldController) {
- super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- stageTaskUnfoldController);
- mContext = context;
- }
-
- void addTask(ActivityManager.RunningTaskInfo task, Rect rootBounds,
- WindowContainerTransaction wct) {
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setBounds(rootToken, rootBounds)
- .reparent(task.token, rootToken, true /* onTop*/)
- // Moving the root task to top after the child tasks were reparented , or the root
- // task cannot be visible and focused.
- .reorder(rootToken, true /* onTop */);
- }
-
- boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
- // No matter if the root task is empty or not, moving the root to bottom because it no
- // longer preserves visible child task.
- wct.reorder(mRootTaskInfo.token, false /* onTop */);
- if (mChildrenTaskInfo.size() == 0) return false;
- wct.reparentTasks(
- mRootTaskInfo.token,
- null /* newParent */,
- CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
- CONTROLLED_ACTIVITY_TYPES,
- toTop);
- return true;
- }
-
- boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) {
- final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId);
- if (task == null) return false;
- wct.reparent(task.token, newParent, false /* onTop */);
- return true;
- }
-
- @Nullable
- public SurfaceControl getOutlineLeash() {
- return mOutlineManager.getOutlineLeash();
- }
-
- @Override
- @CallSuper
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- super.onTaskAppeared(taskInfo, leash);
- if (isRootTask(taskInfo)) {
- mOutlineManager = new OutlineManager(mContext, taskInfo.configuration);
- enableOutline(true);
- }
- }
-
- @Override
- @CallSuper
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- super.onTaskInfoChanged(taskInfo);
- if (isRootTask(taskInfo)) {
- mOutlineManager.setRootBounds(taskInfo.configuration.windowConfiguration.getBounds());
- }
- }
-
- private boolean isRootTask(ActivityManager.RunningTaskInfo taskInfo) {
- return mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId;
- }
-
- void enableOutline(boolean enable) {
- if (mOutlineManager == null) {
- return;
- }
-
- if (enable) {
- if (mRootTaskInfo != null) {
- mOutlineManager.inflate(mRootLeash,
- mRootTaskInfo.configuration.windowConfiguration.getBounds());
- }
- } else {
- mOutlineManager.release();
- }
- }
-
- void setOutlineVisibility(boolean visible) {
- mOutlineManager.setVisibility(visible);
- }
-
- @Override
- public void insetsChanged(InsetsState insetsState) {
- mOutlineManager.onInsetsChanged(insetsState);
- }
-
- @Override
- public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
- insetsChanged(insetsState);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreen.java
deleted file mode 100644
index c5d231262cd2..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreen.java
+++ /dev/null
@@ -1,99 +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.stagesplit;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
-
-import java.util.concurrent.Executor;
-
-/**
- * Interface to engage split-screen feature.
- * TODO: Figure out which of these are actually needed outside of the Shell
- */
-@ExternalThread
-public interface SplitScreen {
- /**
- * Stage type isn't specified normally meaning to use what ever the default is.
- * E.g. exit split-screen and launch the app in fullscreen.
- */
- int STAGE_TYPE_UNDEFINED = -1;
- /**
- * The main stage type.
- * @see MainStage
- */
- int STAGE_TYPE_MAIN = 0;
-
- /**
- * The side stage type.
- * @see SideStage
- */
- int STAGE_TYPE_SIDE = 1;
-
- @IntDef(prefix = { "STAGE_TYPE_" }, value = {
- STAGE_TYPE_UNDEFINED,
- STAGE_TYPE_MAIN,
- STAGE_TYPE_SIDE
- })
- @interface StageType {}
-
- /** Callback interface for listening to changes in a split-screen stage. */
- interface SplitScreenListener {
- default void onStagePositionChanged(@StageType int stage, @SplitPosition int position) {}
- default void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {}
- default void onSplitVisibilityChanged(boolean visible) {}
- }
-
- /** Registers listener that gets split screen callback. */
- void registerSplitScreenListener(@NonNull SplitScreenListener listener,
- @NonNull Executor executor);
-
- /** Unregisters listener that gets split screen callback. */
- void unregisterSplitScreenListener(@NonNull SplitScreenListener listener);
-
- /**
- * Returns a binder that can be passed to an external process to manipulate SplitScreen.
- */
- default ISplitScreen createExternalInterface() {
- return null;
- }
-
- /**
- * Called when the keyguard occluded state changes.
- * @param occluded Indicates if the keyguard is now occluded.
- */
- void onKeyguardOccludedChanged(boolean occluded);
-
- /**
- * Called when the visibility of the keyguard changes.
- * @param showing Indicates if the keyguard is now visible.
- */
- void onKeyguardVisibilityChanged(boolean showing);
-
- /** Get a string representation of a stage type */
- static String stageTypeToString(@StageType int stage) {
- switch (stage) {
- case STAGE_TYPE_UNDEFINED: return "UNDEFINED";
- case STAGE_TYPE_MAIN: return "MAIN";
- case STAGE_TYPE_SIDE: return "SIDE";
- default: return "UNKNOWN(" + stage + ")";
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenController.java
deleted file mode 100644
index 07174051a344..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenController.java
+++ /dev/null
@@ -1,595 +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.stagesplit;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
-
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.Slog;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.view.WindowManager;
-import android.window.RemoteTransition;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.InstanceId;
-import com.android.internal.util.FrameworkStatsLog;
-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;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy;
-import com.android.wm.shell.transition.LegacyTransitions;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-
-import javax.inject.Provider;
-
-/**
- * Class manages split-screen multitasking mode and implements the main interface
- * {@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();
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final SyncTransactionQueue mSyncQueue;
- private final Context mContext;
- private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
- 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;
- private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider;
-
- private StageCoordinator mStageCoordinator;
-
- public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, Context context,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer,
- ShellExecutor mainExecutor, DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController,
- Transitions transitions, TransactionPool transactionPool,
- Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
- mTaskOrganizer = shellTaskOrganizer;
- mSyncQueue = syncQueue;
- mContext = context;
- mRootTDAOrganizer = rootTDAOrganizer;
- mMainExecutor = mainExecutor;
- mDisplayImeController = displayImeController;
- mDisplayInsetsController = displayInsetsController;
- mTransitions = transitions;
- mTransactionPool = transactionPool;
- mUnfoldControllerProvider = unfoldControllerProvider;
- mLogger = new SplitscreenEventLogger();
- }
-
- public SplitScreen asSplitScreen() {
- return mImpl;
- }
-
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mMainExecutor;
- }
-
- public void onOrganizerRegistered() {
- if (mStageCoordinator == null) {
- // TODO: Multi-display
- mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
- mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
- mUnfoldControllerProvider);
- }
- }
-
- public boolean isSplitScreenVisible() {
- return mStageCoordinator.isSplitScreenVisible();
- }
-
- public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
- final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
- if (task == null) {
- throw new IllegalArgumentException("Unknown taskId" + taskId);
- }
- return moveToSideStage(task, sideStagePosition);
- }
-
- public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
- @SplitPosition int sideStagePosition) {
- return mStageCoordinator.moveToSideStage(task, sideStagePosition);
- }
-
- public boolean removeFromSideStage(int taskId) {
- return mStageCoordinator.removeFromSideStage(taskId);
- }
-
- public void setSideStageOutline(boolean enable) {
- mStageCoordinator.setSideStageOutline(enable);
- }
-
- public void setSideStagePosition(@SplitPosition int sideStagePosition) {
- mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
- }
-
- public void setSideStageVisibility(boolean visible) {
- mStageCoordinator.setSideStageVisibility(visible);
- }
-
- public void enterSplitScreen(int taskId, boolean leftOrTop) {
- moveToSideStage(taskId,
- leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
- }
-
- public void exitSplitScreen(int toTopTaskId, int exitReason) {
- mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
- }
-
- public void onKeyguardOccludedChanged(boolean occluded) {
- mStageCoordinator.onKeyguardOccludedChanged(occluded);
- }
-
- public void onKeyguardVisibilityChanged(boolean showing) {
- mStageCoordinator.onKeyguardVisibilityChanged(showing);
- }
-
- public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
- }
-
- public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
- mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds);
- }
-
- public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
- mStageCoordinator.registerSplitScreenListener(listener);
- }
-
- public void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
- mStageCoordinator.unregisterSplitScreenListener(listener);
- }
-
- public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) {
- options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
- null /* wct */);
-
- try {
- ActivityTaskManager.getService().startActivityFromRecents(taskId, options);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to launch task", e);
- }
- }
-
- public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
- @Nullable Bundle options, UserHandle user) {
- options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
- null /* wct */);
-
- try {
- LauncherApps launcherApps =
- mContext.getSystemService(LauncherApps.class);
- launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
- options, user);
- } catch (ActivityNotFoundException e) {
- Slog.e(TAG, "Failed to launch shortcut", e);
- }
- }
-
- public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
- @Nullable Bundle options) {
- if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
- startIntentLegacy(intent, fillInIntent, position, options);
- return;
- }
- mStageCoordinator.startIntent(intent, fillInIntent, STAGE_TYPE_UNDEFINED, position, options,
- null /* remote */);
- }
-
- private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
- @SplitPosition int position, @Nullable Bundle options) {
- LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
- @Override
- public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
- IRemoteAnimationFinishedCallback finishedCallback,
- SurfaceControl.Transaction t) {
- mStageCoordinator.updateSurfaceBounds(null /* layout */, t,
- false /* applyResizingOffset */);
-
- if (apps != null) {
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) {
- t.show(apps[i].leash);
- }
- }
- }
-
- t.apply();
- if (finishedCallback != null) {
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error finishing legacy transition: ", e);
- }
- }
- }
- };
- WindowContainerTransaction wct = new WindowContainerTransaction();
- options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
- wct.sendPendingIntent(intent, fillInIntent, options);
- mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
- }
-
- RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
- if (!isSplitScreenVisible()) return null;
- final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
- .setContainerLayer()
- .setName("RecentsAnimationSplitTasks")
- .setHidden(false)
- .setCallsite("SplitScreenController#onGoingtoRecentsLegacy");
- 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) {
- transaction.reparent(appTarget.leash, sc);
- transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
- appTarget.screenSpaceBounds.top);
- transaction.setLayer(appTarget.leash, layer++);
- }
- transaction.apply();
- transaction.close();
- return new RemoteAnimationTarget[]{
- mStageCoordinator.getDividerBarLegacyTarget(),
- mStageCoordinator.getOutlineLegacyTarget()};
- }
-
- /**
- * Sets drag info to be logged when splitscreen is entered.
- */
- public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
- mStageCoordinator.logOnDroppedToSplit(position, dragSessionId);
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- pw.println(prefix + TAG);
- if (mStageCoordinator != null) {
- mStageCoordinator.dump(pw, prefix);
- }
- }
-
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
- @ExternalThread
- private class SplitScreenImpl implements SplitScreen {
- private ISplitScreenImpl mISplitScreen;
- private final ArrayMap<SplitScreenListener, Executor> mExecutors = new ArrayMap<>();
- private final SplitScreenListener mListener = new SplitScreenListener() {
- @Override
- public void onStagePositionChanged(int stage, int position) {
- for (int i = 0; i < mExecutors.size(); i++) {
- final int index = i;
- mExecutors.valueAt(index).execute(() -> {
- mExecutors.keyAt(index).onStagePositionChanged(stage, position);
- });
- }
- }
-
- @Override
- public void onTaskStageChanged(int taskId, int stage, boolean visible) {
- for (int i = 0; i < mExecutors.size(); i++) {
- final int index = i;
- mExecutors.valueAt(index).execute(() -> {
- mExecutors.keyAt(index).onTaskStageChanged(taskId, stage, visible);
- });
- }
- }
-
- @Override
- public void onSplitVisibilityChanged(boolean visible) {
- for (int i = 0; i < mExecutors.size(); i++) {
- final int index = i;
- mExecutors.valueAt(index).execute(() -> {
- mExecutors.keyAt(index).onSplitVisibilityChanged(visible);
- });
- }
- }
- };
-
- @Override
- public ISplitScreen createExternalInterface() {
- if (mISplitScreen != null) {
- mISplitScreen.invalidate();
- }
- mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
- return mISplitScreen;
- }
-
- @Override
- public void onKeyguardOccludedChanged(boolean occluded) {
- mMainExecutor.execute(() -> {
- SplitScreenController.this.onKeyguardOccludedChanged(occluded);
- });
- }
-
- @Override
- public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
- if (mExecutors.containsKey(listener)) return;
-
- mMainExecutor.execute(() -> {
- if (mExecutors.size() == 0) {
- SplitScreenController.this.registerSplitScreenListener(mListener);
- }
-
- mExecutors.put(listener, executor);
- });
-
- executor.execute(() -> {
- mStageCoordinator.sendStatusToListener(listener);
- });
- }
-
- @Override
- public void unregisterSplitScreenListener(SplitScreenListener listener) {
- mMainExecutor.execute(() -> {
- mExecutors.remove(listener);
-
- if (mExecutors.size() == 0) {
- SplitScreenController.this.unregisterSplitScreenListener(mListener);
- }
- });
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- mMainExecutor.execute(() -> {
- SplitScreenController.this.onKeyguardVisibilityChanged(showing);
- });
- }
- }
-
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class ISplitScreenImpl extends ISplitScreen.Stub {
- private SplitScreenController mController;
- private ISplitScreenListener mListener;
- private final SplitScreen.SplitScreenListener mSplitScreenListener =
- new SplitScreen.SplitScreenListener() {
- @Override
- public void onStagePositionChanged(int stage, int position) {
- try {
- if (mListener != null) {
- mListener.onStagePositionChanged(stage, position);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onStagePositionChanged", e);
- }
- }
-
- @Override
- public void onTaskStageChanged(int taskId, int stage, boolean visible) {
- try {
- if (mListener != null) {
- mListener.onTaskStageChanged(taskId, stage, visible);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onTaskStageChanged", e);
- }
- }
- };
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final SplitScreenController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
- }
- };
-
- public ISplitScreenImpl(SplitScreenController controller) {
- mController = controller;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mController = null;
- }
-
- @Override
- public void registerSplitScreenListener(ISplitScreenListener listener) {
- executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- if (listener != null) {
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
- }
- mListener = listener;
- controller.registerSplitScreenListener(mSplitScreenListener);
- });
- }
-
- @Override
- public void unregisterSplitScreenListener(ISplitScreenListener listener) {
- executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
- }
-
- @Override
- public void exitSplitScreen(int toTopTaskId) {
- executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
- (controller) -> {
- controller.exitSplitScreen(toTopTaskId,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT);
- });
- }
-
- @Override
- public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide",
- (controller) -> {
- controller.exitSplitScreenOnHide(exitSplitScreenOnHide);
- });
- }
-
- @Override
- public void setSideStageVisibility(boolean visible) {
- executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
- (controller) -> {
- controller.setSideStageVisibility(visible);
- });
- }
-
- @Override
- public void removeFromSideStage(int taskId) {
- executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
- (controller) -> {
- controller.removeFromSideStage(taskId);
- });
- }
-
- @Override
- public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
- executeRemoteCallWithTaskPermission(mController, "startTask",
- (controller) -> {
- controller.startTask(taskId, position, options);
- });
- }
-
- @Override
- public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
- int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- RemoteAnimationAdapter adapter) {
- executeRemoteCallWithTaskPermission(mController, "startTasks",
- (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
- mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
- adapter));
- }
-
- @Override
- public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
- int sideTaskId, @Nullable Bundle sideOptions,
- @SplitPosition int sidePosition,
- @Nullable RemoteTransition remoteTransition) {
- executeRemoteCallWithTaskPermission(mController, "startTasks",
- (controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
- sideTaskId, sideOptions, sidePosition, remoteTransition));
- }
-
- @Override
- public void startShortcut(String packageName, String shortcutId, int stage, int position,
- @Nullable Bundle options, UserHandle user) {
- executeRemoteCallWithTaskPermission(mController, "startShortcut",
- (controller) -> {
- controller.startShortcut(packageName, shortcutId, position,
- options, user);
- });
- }
-
- @Override
- public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
- @Nullable Bundle options) {
- executeRemoteCallWithTaskPermission(mController, "startIntent",
- (controller) -> {
- controller.startIntent(intent, fillInIntent, position, options);
- });
- }
-
- @Override
- public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
- RemoteAnimationTarget[] apps) {
- final RemoteAnimationTarget[][] out = new RemoteAnimationTarget[][]{null};
- executeRemoteCallWithTaskPermission(mController, "onGoingToRecentsLegacy",
- (controller) -> out[0] = controller.onGoingToRecentsLegacy(cancel, apps),
- true /* blocking */);
- return out[0];
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java
deleted file mode 100644
index 018365420177..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java
+++ /dev/null
@@ -1,292 +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.stagesplit;
-
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
-
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
-import static com.android.wm.shell.transition.Transitions.isOpeningType;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.window.RemoteTransition;
-import android.window.TransitionInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.transition.OneShotRemoteHandler;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-
-/** Manages transition animations for split-screen. */
-class SplitScreenTransitions {
- private static final String TAG = "SplitScreenTransitions";
-
- /** Flag applied to a transition change to identify it as a divider bar for animation. */
- public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
-
- private final TransactionPool mTransactionPool;
- private final Transitions mTransitions;
- private final Runnable mOnFinish;
-
- IBinder mPendingDismiss = null;
- IBinder mPendingEnter = null;
-
- private IBinder mAnimatingTransition = null;
- private OneShotRemoteHandler mRemoteHandler = null;
-
- private Transitions.TransitionFinishCallback mRemoteFinishCB = (wct, wctCB) -> {
- if (wct != null || wctCB != null) {
- throw new UnsupportedOperationException("finish transactions not supported yet.");
- }
- onFinish();
- };
-
- /** Keeps track of currently running animations */
- private final ArrayList<Animator> mAnimations = new ArrayList<>();
-
- private Transitions.TransitionFinishCallback mFinishCallback = null;
- private SurfaceControl.Transaction mFinishTransaction;
-
- SplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
- @NonNull Runnable onFinishCallback) {
- mTransactionPool = pool;
- mTransitions = transitions;
- mOnFinish = onFinishCallback;
- }
-
- void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback,
- @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot) {
- mFinishCallback = finishCallback;
- mAnimatingTransition = transition;
- if (mRemoteHandler != null) {
- mRemoteHandler.startAnimation(transition, info, startTransaction, finishTransaction,
- mRemoteFinishCB);
- mRemoteHandler = null;
- return;
- }
- playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot);
- }
-
- private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
- @NonNull WindowContainerToken sideRoot) {
- mFinishTransaction = mTransactionPool.acquire();
-
- // Play some place-holder fade animations
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final SurfaceControl leash = change.getLeash();
- final int mode = info.getChanges().get(i).getMode();
-
- if (mode == TRANSIT_CHANGE) {
- if (change.getParent() != null) {
- // This is probably reparented, so we want the parent to be immediately visible
- final TransitionInfo.Change parentChange = info.getChange(change.getParent());
- t.show(parentChange.getLeash());
- t.setAlpha(parentChange.getLeash(), 1.f);
- // and then animate this layer outside the parent (since, for example, this is
- // the home task animating from fullscreen to part-screen).
- t.reparent(leash, info.getRootLeash());
- t.setLayer(leash, info.getChanges().size() - i);
- // build the finish reparent/reposition
- mFinishTransaction.reparent(leash, parentChange.getLeash());
- mFinishTransaction.setPosition(leash,
- change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- // TODO(shell-transitions): screenshot here
- final Rect startBounds = new Rect(change.getStartAbsBounds());
- final Rect endBounds = new Rect(change.getEndAbsBounds());
- startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
- startExampleResizeAnimation(leash, startBounds, endBounds);
- }
- if (change.getParent() != null) {
- continue;
- }
-
- if (transition == mPendingEnter && (mainRoot.equals(change.getContainer())
- || sideRoot.equals(change.getContainer()))) {
- t.setWindowCrop(leash, change.getStartAbsBounds().width(),
- change.getStartAbsBounds().height());
- }
- boolean isOpening = isOpeningType(info.getType());
- if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
- // fade in
- startExampleAnimation(leash, true /* show */);
- } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
- // fade out
- if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
- // Dismissing via snap-to-top/bottom means that the dismissed task is already
- // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
- // and don't animate it so it doesn't pop-in when reparented.
- t.setAlpha(leash, 0.f);
- } else {
- startExampleAnimation(leash, false /* show */);
- }
- }
- }
- t.apply();
- onFinish();
- }
-
- /** Starts a transition to enter split with a remote transition animator. */
- IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
- @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)
- mRemoteHandler = new OneShotRemoteHandler(
- mTransitions.getMainExecutor(), remoteTransition);
- }
- final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
- mPendingEnter = transition;
- if (mRemoteHandler != null) {
- mRemoteHandler.setTransition(transition);
- }
- return transition;
- }
-
- /** Starts a transition for dismissing split after dragging the divider to a screen edge */
- IBinder startSnapToDismiss(@NonNull WindowContainerTransaction wct,
- @NonNull Transitions.TransitionHandler handler) {
- final IBinder transition = mTransitions.startTransition(
- TRANSIT_SPLIT_DISMISS_SNAP, wct, handler);
- mPendingDismiss = transition;
- return transition;
- }
-
- void onFinish() {
- if (!mAnimations.isEmpty()) return;
- mOnFinish.run();
- if (mFinishTransaction != null) {
- mFinishTransaction.apply();
- mTransactionPool.release(mFinishTransaction);
- mFinishTransaction = null;
- }
- mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
- mFinishCallback = null;
- if (mAnimatingTransition == mPendingEnter) {
- mPendingEnter = null;
- }
- if (mAnimatingTransition == mPendingDismiss) {
- mPendingDismiss = null;
- }
- mAnimatingTransition = null;
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) {
- final float end = show ? 1.f : 0.f;
- final float start = 1.f - end;
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(start, end);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setAlpha(leash, end);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) { }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) { }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-
- // TODO(shell-transitions): real animations
- private void startExampleResizeAnimation(@NonNull SurfaceControl leash,
- @NonNull Rect startBounds, @NonNull Rect endBounds) {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f);
- va.setDuration(500);
- va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setWindowCrop(leash,
- (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction),
- (int) (startBounds.height() * (1.f - fraction)
- + endBounds.height() * fraction));
- transaction.setPosition(leash,
- startBounds.left * (1.f - fraction) + endBounds.left * fraction,
- startBounds.top * (1.f - fraction) + endBounds.top * fraction);
- transaction.apply();
- });
- final Runnable finisher = () -> {
- transaction.setWindowCrop(leash, 0, 0);
- transaction.setPosition(leash, endBounds.left, endBounds.top);
- transaction.apply();
- mTransactionPool.release(transaction);
- mTransitions.getMainExecutor().execute(() -> {
- mAnimations.remove(va);
- onFinish();
- });
- };
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finisher.run();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- finisher.run();
- }
- });
- mAnimations.add(va);
- mTransitions.getAnimExecutor().execute(va::start);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitscreenEventLogger.java
deleted file mode 100644
index e1850396a5c0..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitscreenEventLogger.java
+++ /dev/null
@@ -1,324 +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.stagesplit;
-
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-
-import com.android.internal.logging.InstanceId;
-import com.android.internal.logging.InstanceIdSequence;
-import com.android.internal.util.FrameworkStatsLog;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
-
-/**
- * Helper class that to log Drag & Drop UIEvents for a single session, see also go/uievent
- */
-public class SplitscreenEventLogger {
-
- // Used to generate instance ids for this drag if one is not provided
- private final InstanceIdSequence mIdSequence;
-
- // The instance id for the current splitscreen session (from start to end)
- private InstanceId mLoggerSessionId;
-
- // Drag info
- private @SplitPosition int mDragEnterPosition;
- private InstanceId mDragEnterSessionId;
-
- // For deduping async events
- private int mLastMainStagePosition = -1;
- private int mLastMainStageUid = -1;
- private int mLastSideStagePosition = -1;
- private int mLastSideStageUid = -1;
- private float mLastSplitRatio = -1f;
-
- public SplitscreenEventLogger() {
- mIdSequence = new InstanceIdSequence(Integer.MAX_VALUE);
- }
-
- /**
- * Return whether a splitscreen session has started.
- */
- public boolean hasStartedSession() {
- return mLoggerSessionId != null;
- }
-
- /**
- * May be called before logEnter() to indicate that the session was started from a drag.
- */
- public void enterRequestedByDrag(@SplitPosition int position, InstanceId dragSessionId) {
- mDragEnterPosition = position;
- mDragEnterSessionId = dragSessionId;
- }
-
- /**
- * Logs when the user enters splitscreen.
- */
- public void logEnter(float splitRatio,
- @SplitPosition int mainStagePosition, int mainStageUid,
- @SplitPosition int sideStagePosition, int sideStageUid,
- boolean isLandscape) {
- mLoggerSessionId = mIdSequence.newInstanceId();
- int enterReason = mDragEnterPosition != SPLIT_POSITION_UNDEFINED
- ? getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape)
- : SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
- updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
- mainStageUid);
- updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
- sideStageUid);
- updateSplitRatioState(splitRatio);
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__ENTER,
- enterReason,
- 0 /* exitReason */,
- splitRatio,
- mLastMainStagePosition,
- mLastMainStageUid,
- mLastSideStagePosition,
- mLastSideStageUid,
- mDragEnterSessionId != null ? mDragEnterSessionId.getId() : 0,
- mLoggerSessionId.getId());
- }
-
- /**
- * Logs when the user exits splitscreen. Only one of the main or side stages should be
- * specified to indicate which position was focused as a part of exiting (both can be unset).
- */
- public void logExit(int exitReason, @SplitPosition int mainStagePosition, int mainStageUid,
- @SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
- if (mLoggerSessionId == null) {
- // Ignore changes until we've started logging the session
- return;
- }
- if ((mainStagePosition != SPLIT_POSITION_UNDEFINED
- && sideStagePosition != SPLIT_POSITION_UNDEFINED)
- || (mainStageUid != 0 && sideStageUid != 0)) {
- throw new IllegalArgumentException("Only main or side stage should be set");
- }
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__EXIT,
- 0 /* enterReason */,
- exitReason,
- 0f /* splitRatio */,
- getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
- mainStageUid,
- getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
- sideStageUid,
- 0 /* dragInstanceId */,
- mLoggerSessionId.getId());
-
- // Reset states
- mLoggerSessionId = null;
- mDragEnterPosition = SPLIT_POSITION_UNDEFINED;
- mDragEnterSessionId = null;
- mLastMainStagePosition = -1;
- mLastMainStageUid = -1;
- mLastSideStagePosition = -1;
- mLastSideStageUid = -1;
- }
-
- /**
- * Logs when an app in the main stage changes.
- */
- public void logMainStageAppChange(@SplitPosition int mainStagePosition, int mainStageUid,
- boolean isLandscape) {
- if (mLoggerSessionId == null) {
- // Ignore changes until we've started logging the session
- return;
- }
- if (!updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition,
- isLandscape), mainStageUid)) {
- // Ignore if there are no user perceived changes
- return;
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__APP_CHANGE,
- 0 /* enterReason */,
- 0 /* exitReason */,
- 0f /* splitRatio */,
- mLastMainStagePosition,
- mLastMainStageUid,
- 0 /* sideStagePosition */,
- 0 /* sideStageUid */,
- 0 /* dragInstanceId */,
- mLoggerSessionId.getId());
- }
-
- /**
- * Logs when an app in the side stage changes.
- */
- public void logSideStageAppChange(@SplitPosition int sideStagePosition, int sideStageUid,
- boolean isLandscape) {
- if (mLoggerSessionId == null) {
- // Ignore changes until we've started logging the session
- return;
- }
- if (!updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition,
- isLandscape), sideStageUid)) {
- // Ignore if there are no user perceived changes
- return;
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__APP_CHANGE,
- 0 /* enterReason */,
- 0 /* exitReason */,
- 0f /* splitRatio */,
- 0 /* mainStagePosition */,
- 0 /* mainStageUid */,
- mLastSideStagePosition,
- mLastSideStageUid,
- 0 /* dragInstanceId */,
- mLoggerSessionId.getId());
- }
-
- /**
- * Logs when the splitscreen ratio changes.
- */
- public void logResize(float splitRatio) {
- if (mLoggerSessionId == null) {
- // Ignore changes until we've started logging the session
- return;
- }
- if (splitRatio <= 0f || splitRatio >= 1f) {
- // Don't bother reporting resizes that end up dismissing the split, that will be logged
- // via the exit event
- return;
- }
- if (!updateSplitRatioState(splitRatio)) {
- // Ignore if there are no user perceived changes
- return;
- }
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__RESIZE,
- 0 /* enterReason */,
- 0 /* exitReason */,
- mLastSplitRatio,
- 0 /* mainStagePosition */, 0 /* mainStageUid */,
- 0 /* sideStagePosition */, 0 /* sideStageUid */,
- 0 /* dragInstanceId */,
- mLoggerSessionId.getId());
- }
-
- /**
- * Logs when the apps in splitscreen are swapped.
- */
- public void logSwap(@SplitPosition int mainStagePosition, int mainStageUid,
- @SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
- if (mLoggerSessionId == null) {
- // Ignore changes until we've started logging the session
- return;
- }
-
- updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
- mainStageUid);
- updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
- sideStageUid);
- FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__SWAP,
- 0 /* enterReason */,
- 0 /* exitReason */,
- 0f /* splitRatio */,
- mLastMainStagePosition,
- mLastMainStageUid,
- mLastSideStagePosition,
- mLastSideStageUid,
- 0 /* dragInstanceId */,
- mLoggerSessionId.getId());
- }
-
- private boolean updateMainStageState(int mainStagePosition, int mainStageUid) {
- boolean changed = (mLastMainStagePosition != mainStagePosition)
- || (mLastMainStageUid != mainStageUid);
- if (!changed) {
- return false;
- }
-
- mLastMainStagePosition = mainStagePosition;
- mLastMainStageUid = mainStageUid;
- return true;
- }
-
- private boolean updateSideStageState(int sideStagePosition, int sideStageUid) {
- boolean changed = (mLastSideStagePosition != sideStagePosition)
- || (mLastSideStageUid != sideStageUid);
- if (!changed) {
- return false;
- }
-
- mLastSideStagePosition = sideStagePosition;
- mLastSideStageUid = sideStageUid;
- return true;
- }
-
- private boolean updateSplitRatioState(float splitRatio) {
- boolean changed = Float.compare(mLastSplitRatio, splitRatio) != 0;
- if (!changed) {
- return false;
- }
-
- mLastSplitRatio = splitRatio;
- return true;
- }
-
- public int getDragEnterReasonFromSplitPosition(@SplitPosition int position,
- boolean isLandscape) {
- if (isLandscape) {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_LEFT
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_RIGHT;
- } else {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_TOP
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_BOTTOM;
- }
- }
-
- private int getMainStagePositionFromSplitPosition(@SplitPosition int position,
- boolean isLandscape) {
- if (position == SPLIT_POSITION_UNDEFINED) {
- return 0;
- }
- if (isLandscape) {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__LEFT
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__RIGHT;
- } else {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__TOP
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__BOTTOM;
- }
- }
-
- private int getSideStagePositionFromSplitPosition(@SplitPosition int position,
- boolean isLandscape) {
- if (position == SPLIT_POSITION_UNDEFINED) {
- return 0;
- }
- if (isLandscape) {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__LEFT
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__RIGHT;
- } else {
- return position == SPLIT_POSITION_TOP_OR_LEFT
- ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__TOP
- : FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__BOTTOM;
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
deleted file mode 100644
index ac25c7510931..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
+++ /dev/null
@@ -1,1333 +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.stagesplit;
-
-import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
-
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.stagesplit.SplitScreen.STAGE_TYPE_MAIN;
-import static com.android.wm.shell.stagesplit.SplitScreen.STAGE_TYPE_SIDE;
-import static com.android.wm.shell.stagesplit.SplitScreen.STAGE_TYPE_UNDEFINED;
-import static com.android.wm.shell.stagesplit.SplitScreen.stageTypeToString;
-import static com.android.wm.shell.stagesplit.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
-import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
-import static com.android.wm.shell.transition.Transitions.isClosingType;
-import static com.android.wm.shell.transition.Transitions.isOpeningType;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.WindowConfiguration;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.hardware.devicestate.DeviceStateManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Slog;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.view.WindowManager;
-import android.window.DisplayAreaInfo;
-import android.window.RemoteTransition;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
-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;
-import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
-import com.android.wm.shell.common.split.SplitWindowManager;
-import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-import javax.inject.Provider;
-
-/**
- * Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and
- * {@link SideStage} stages.
- * Some high-level rules:
- * - The {@link StageCoordinator} is only considered active if the {@link SideStage} contains at
- * least one child task.
- * - The {@link MainStage} should only have children if the coordinator is active.
- * - The {@link SplitLayout} divider is only visible if both the {@link MainStage}
- * and {@link SideStage} are visible.
- * - The {@link MainStage} configuration is fullscreen when the {@link SideStage} isn't visible.
- * This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
- * {@link #onStageHasChildrenChanged(StageListenerImpl).}
- */
-class StageCoordinator implements SplitLayout.SplitLayoutHandler,
- RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
-
- private static final String TAG = StageCoordinator.class.getSimpleName();
-
- /** internal value for mDismissTop that represents no dismiss */
- private static final int NO_DISMISS = -2;
-
- private final SurfaceSession mSurfaceSession = new SurfaceSession();
-
- private final MainStage mMainStage;
- private final StageListenerImpl mMainStageListener = new StageListenerImpl();
- private final StageTaskUnfoldController mMainUnfoldController;
- private final SideStage mSideStage;
- private final StageListenerImpl mSideStageListener = new StageListenerImpl();
- private final StageTaskUnfoldController mSideUnfoldController;
- @SplitPosition
- private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
-
- private final int mDisplayId;
- private SplitLayout mSplitLayout;
- private boolean mDividerVisible;
- private final SyncTransactionQueue mSyncQueue;
- private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
- private final ShellTaskOrganizer mTaskOrganizer;
- private DisplayAreaInfo mDisplayAreaInfo;
- 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;
- private boolean mKeyguardOccluded;
-
- // TODO(b/187041611): remove this flag after totally deprecated legacy split
- /** Whether the device is supporting legacy split or not. */
- private boolean mUseLegacySplit;
-
- @SplitScreen.StageType private int mDismissTop = NO_DISMISS;
-
- /** The target stage to dismiss to when unlock after folded. */
- @SplitScreen.StageType private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
-
- private final Runnable mOnTransitionAnimationComplete = () -> {
- // If still playing, let it finish.
- if (!isSplitScreenVisible()) {
- // Update divider state after animation so that it is still around and positioned
- // properly for the animation itself.
- setDividerVisibility(false);
- mSplitLayout.resetDividerPosition();
- }
- mDismissTop = NO_DISMISS;
- };
-
- private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
- new SplitWindowManager.ParentContainerCallbacks() {
- @Override
- public void attachToParentSurface(SurfaceControl.Builder b) {
- mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b);
- }
-
- @Override
- public void onLeashReady(SurfaceControl leash) {
- mSyncQueue.runInSync(t -> applyDividerVisibility(t));
- }
- };
-
- StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController, Transitions transitions,
- TransactionPool transactionPool, SplitscreenEventLogger logger,
- Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
- mContext = context;
- mDisplayId = displayId;
- mSyncQueue = syncQueue;
- mRootTDAOrganizer = rootTDAOrganizer;
- mTaskOrganizer = taskOrganizer;
- mLogger = logger;
- mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
- mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
-
- mMainStage = new MainStage(
- mTaskOrganizer,
- mDisplayId,
- mMainStageListener,
- mSyncQueue,
- mSurfaceSession,
- mMainUnfoldController);
- mSideStage = new SideStage(
- mContext,
- mTaskOrganizer,
- mDisplayId,
- mSideStageListener,
- mSyncQueue,
- mSurfaceSession,
- mSideUnfoldController);
- mDisplayImeController = displayImeController;
- mDisplayInsetsController = displayInsetsController;
- mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage);
- mRootTDAOrganizer.registerListener(displayId, this);
- final DeviceStateManager deviceStateManager =
- mContext.getSystemService(DeviceStateManager.class);
- deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
- new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
- mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
- mOnTransitionAnimationComplete);
- transitions.addHandler(this);
- }
-
- @VisibleForTesting
- StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
- DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
- Transitions transitions, TransactionPool transactionPool,
- SplitscreenEventLogger logger,
- Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
- mContext = context;
- mDisplayId = displayId;
- mSyncQueue = syncQueue;
- mRootTDAOrganizer = rootTDAOrganizer;
- mTaskOrganizer = taskOrganizer;
- mMainStage = mainStage;
- mSideStage = sideStage;
- mDisplayImeController = displayImeController;
- mDisplayInsetsController = displayInsetsController;
- mRootTDAOrganizer.registerListener(displayId, this);
- mSplitLayout = splitLayout;
- mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
- mOnTransitionAnimationComplete);
- mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
- mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
- mLogger = logger;
- transitions.addHandler(this);
- }
-
- @VisibleForTesting
- SplitScreenTransitions getSplitTransitions() {
- return mSplitTransitions;
- }
-
- boolean isSplitScreenVisible() {
- return mSideStageListener.mVisible && mMainStageListener.mVisible;
- }
-
- boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
- @SplitPosition int sideStagePosition) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- setSideStagePosition(sideStagePosition, wct);
- mMainStage.activate(getMainStageBounds(), wct);
- mSideStage.addTask(task, getSideStageBounds(), wct);
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(
- t -> updateSurfaceBounds(null /* layout */, t, false /* applyResizingOffset */));
- return true;
- }
-
- boolean removeFromSideStage(int taskId) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- /**
- * {@link MainStage} will be deactivated in {@link #onStageHasChildrenChanged} if the
- * {@link SideStage} no longer has children.
- */
- final boolean result = mSideStage.removeTask(taskId,
- mMainStage.isActive() ? mMainStage.mRootTaskInfo.token : null,
- wct);
- mTaskOrganizer.applyTransaction(wct);
- return result;
- }
-
- void setSideStageOutline(boolean enable) {
- mSideStage.enableOutline(enable);
- }
-
- /** Starts 2 tasks in one transition. */
- void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
- @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- @Nullable RemoteTransition remoteTransition) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mainOptions = mainOptions != null ? mainOptions : new Bundle();
- sideOptions = sideOptions != null ? sideOptions : new Bundle();
- setSideStagePosition(sidePosition, wct);
-
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct);
- mSideStage.setBounds(getSideStageBounds(), wct);
-
- // Make sure the launch options will put tasks in the corresponding split roots
- addActivityOptions(mainOptions, mMainStage);
- addActivityOptions(sideOptions, mSideStage);
-
- // Add task launch requests
- wct.startTask(mainTaskId, mainOptions);
- wct.startTask(sideTaskId, sideOptions);
-
- mSplitTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this);
- }
-
- /** Starts 2 tasks in one legacy transition. */
- void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
- int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- RemoteAnimationAdapter adapter) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Need to add another wrapper here in shell so that we can inject the divider bar
- // and also manage the process elevation via setRunningRemote
- IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- final IRemoteAnimationFinishedCallback finishedCallback) {
- RemoteAnimationTarget[] augmentedNonApps =
- new RemoteAnimationTarget[nonApps.length + 1];
- for (int i = 0; i < nonApps.length; ++i) {
- augmentedNonApps[i] = nonApps[i];
- }
- augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
- try {
- ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
- adapter.getCallingApplication());
- adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps,
- finishedCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- }
-
- @Override
- public void onAnimationCancelled() {
- try {
- adapter.getRunner().onAnimationCancelled();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- }
- };
- RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
- wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
-
- if (mainOptions == null) {
- mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
- } else {
- ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
- mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
- }
-
- sideOptions = sideOptions != null ? sideOptions : new Bundle();
- setSideStagePosition(sidePosition, wct);
-
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct);
- mSideStage.setBounds(getSideStageBounds(), wct);
-
- // Make sure the launch options will put tasks in the corresponding split roots
- addActivityOptions(mainOptions, mMainStage);
- addActivityOptions(sideOptions, mSideStage);
-
- // Add task launch requests
- wct.startTask(mainTaskId, mainOptions);
- wct.startTask(sideTaskId, sideOptions);
-
- // Using legacy transitions, so we can't use blast sync since it conflicts.
- mTaskOrganizer.applyTransaction(wct);
- }
-
- public void startIntent(PendingIntent intent, Intent fillInIntent,
- @SplitScreen.StageType int stage, @SplitPosition int position,
- @androidx.annotation.Nullable Bundle options,
- @Nullable RemoteTransition remoteTransition) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- options = resolveStartStage(stage, position, options, wct);
- wct.sendPendingIntent(intent, fillInIntent, options);
- mSplitTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this);
- }
-
- Bundle resolveStartStage(@SplitScreen.StageType int stage,
- @SplitPosition int position, @androidx.annotation.Nullable Bundle options,
- @androidx.annotation.Nullable WindowContainerTransaction wct) {
- switch (stage) {
- case STAGE_TYPE_UNDEFINED: {
- // Use the stage of the specified position is valid.
- if (position != SPLIT_POSITION_UNDEFINED) {
- if (position == getSideStagePosition()) {
- options = resolveStartStage(STAGE_TYPE_SIDE, position, options, wct);
- } else {
- options = resolveStartStage(STAGE_TYPE_MAIN, position, options, wct);
- }
- } else {
- // Exit split-screen and launch fullscreen since stage wasn't specified.
- prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
- }
- break;
- }
- case STAGE_TYPE_SIDE: {
- if (position != SPLIT_POSITION_UNDEFINED) {
- setSideStagePosition(position, wct);
- } else {
- position = getSideStagePosition();
- }
- if (options == null) {
- options = new Bundle();
- }
- updateActivityOptions(options, position);
- break;
- }
- case STAGE_TYPE_MAIN: {
- if (position != SPLIT_POSITION_UNDEFINED) {
- // Set the side stage opposite of what we want to the main stage.
- final int sideStagePosition = position == SPLIT_POSITION_TOP_OR_LEFT
- ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
- setSideStagePosition(sideStagePosition, wct);
- } else {
- position = getMainStagePosition();
- }
- if (options == null) {
- options = new Bundle();
- }
- updateActivityOptions(options, position);
- break;
- }
- default:
- throw new IllegalArgumentException("Unknown stage=" + stage);
- }
-
- return options;
- }
-
- @SplitPosition
- int getSideStagePosition() {
- return mSideStagePosition;
- }
-
- @SplitPosition
- int getMainStagePosition() {
- return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
- }
-
- void setSideStagePosition(@SplitPosition int sideStagePosition,
- @Nullable WindowContainerTransaction wct) {
- setSideStagePosition(sideStagePosition, true /* updateBounds */, wct);
- }
-
- private void setSideStagePosition(@SplitPosition int sideStagePosition, boolean updateBounds,
- @Nullable WindowContainerTransaction wct) {
- if (mSideStagePosition == sideStagePosition) return;
- mSideStagePosition = sideStagePosition;
- sendOnStagePositionChanged();
-
- if (mSideStageListener.mVisible && updateBounds) {
- if (wct == null) {
- // onLayoutSizeChanged builds/applies a wct with the contents of updateWindowBounds.
- onLayoutSizeChanged(mSplitLayout);
- } else {
- updateWindowBounds(mSplitLayout, wct);
- updateUnfoldBounds();
- }
- }
- }
-
- void setSideStageVisibility(boolean visible) {
- if (mSideStageListener.mVisible == visible) return;
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mSideStage.setVisibility(visible, wct);
- mTaskOrganizer.applyTransaction(wct);
- }
-
- void onKeyguardOccludedChanged(boolean occluded) {
- // Do not exit split directly, because it needs to wait for task info update to determine
- // which task should remain on top after split dismissed.
- mKeyguardOccluded = occluded;
- }
-
- void onKeyguardVisibilityChanged(boolean showing) {
- if (!showing && mMainStage.isActive()
- && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
- exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
- SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED);
- }
- }
-
- void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- mExitSplitScreenOnHide = exitSplitScreenOnHide;
- }
-
- void exitSplitScreen(int toTopTaskId, int exitReason) {
- StageTaskListener childrenToTop = null;
- if (mMainStage.containsTask(toTopTaskId)) {
- childrenToTop = mMainStage;
- } else if (mSideStage.containsTask(toTopTaskId)) {
- childrenToTop = mSideStage;
- }
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- if (childrenToTop != null) {
- childrenToTop.reorderChild(toTopTaskId, true /* onTop */, wct);
- }
- applyExitSplitScreen(childrenToTop, wct, exitReason);
- }
-
- private void exitSplitScreen(StageTaskListener childrenToTop, int exitReason) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- applyExitSplitScreen(childrenToTop, wct, exitReason);
- }
-
- private void applyExitSplitScreen(
- StageTaskListener childrenToTop,
- WindowContainerTransaction wct, int exitReason) {
- mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
- mMainStage.deactivate(wct, childrenToTop == mMainStage);
- mTaskOrganizer.applyTransaction(wct);
- mSyncQueue.runInSync(t -> t
- .setWindowCrop(mMainStage.mRootLeash, null)
- .setWindowCrop(mSideStage.mRootLeash, null));
- // Hide divider and reset its position.
- setDividerVisibility(false);
- mSplitLayout.resetDividerPosition();
- mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
- if (childrenToTop != null) {
- logExitToStage(exitReason, childrenToTop == mMainStage);
- } else {
- logExit(exitReason);
- }
- }
-
- /**
- * Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
- * an existing WindowContainerTransaction (rather than applying immediately). This is intended
- * to be used when exiting split might be bundled with other window operations.
- */
- void prepareExitSplitScreen(@SplitScreen.StageType int stageToTop,
- @NonNull WindowContainerTransaction wct) {
- mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
- mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
- }
-
- void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
- outTopOrLeftBounds.set(mSplitLayout.getBounds1());
- outBottomOrRightBounds.set(mSplitLayout.getBounds2());
- }
-
- private void addActivityOptions(Bundle opts, StageTaskListener stage) {
- opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
- }
-
- void updateActivityOptions(Bundle opts, @SplitPosition int position) {
- addActivityOptions(opts, position == mSideStagePosition ? mSideStage : mMainStage);
- }
-
- void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
- if (mListeners.contains(listener)) return;
- mListeners.add(listener);
- sendStatusToListener(listener);
- }
-
- void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
- mListeners.remove(listener);
- }
-
- void sendStatusToListener(SplitScreen.SplitScreenListener listener) {
- listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
- listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
- listener.onSplitVisibilityChanged(isSplitScreenVisible());
- mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
- mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
- }
-
- private void sendOnStagePositionChanged() {
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- final SplitScreen.SplitScreenListener l = mListeners.get(i);
- l.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
- l.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
- }
- }
-
- private void onStageChildTaskStatusChanged(StageListenerImpl stageListener, int taskId,
- boolean present, boolean visible) {
- int stage;
- if (present) {
- stage = stageListener == mSideStageListener ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
- } else {
- // No longer on any stage
- stage = STAGE_TYPE_UNDEFINED;
- }
- if (stage == STAGE_TYPE_MAIN) {
- mLogger.logMainStageAppChange(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
- } else {
- mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
- }
-
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
- }
- }
-
- private void sendSplitVisibilityChanged() {
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- final SplitScreen.SplitScreenListener l = mListeners.get(i);
- l.onSplitVisibilityChanged(mDividerVisible);
- }
-
- if (mMainUnfoldController != null && mSideUnfoldController != null) {
- mMainUnfoldController.onSplitVisibilityChanged(mDividerVisible);
- mSideUnfoldController.onSplitVisibilityChanged(mDividerVisible);
- }
- }
-
- private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
- if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
- mUseLegacySplit = mContext.getResources().getBoolean(R.bool.config_useLegacySplit);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Make the stages adjacent to each other so they occlude what's behind them.
- wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
- true /* moveTogether */);
-
- // Only sets side stage as launch-adjacent-flag-root when the device is not using legacy
- // split to prevent new split behavior confusing users.
- if (!mUseLegacySplit) {
- wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- }
-
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- private void onStageRootTaskVanished(StageListenerImpl stageListener) {
- if (stageListener == mMainStageListener || stageListener == mSideStageListener) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Deactivate the main stage if it no longer has a root task.
- mMainStage.deactivate(wct);
-
- if (!mUseLegacySplit) {
- wct.clearLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- }
-
- mTaskOrganizer.applyTransaction(wct);
- }
- }
-
- private void setDividerVisibility(boolean visible) {
- if (mDividerVisible == visible) return;
- mDividerVisible = visible;
- if (visible) {
- mSplitLayout.init();
- updateUnfoldBounds();
- } else {
- mSplitLayout.release();
- }
- sendSplitVisibilityChanged();
- }
-
- private void onStageVisibilityChanged(StageListenerImpl stageListener) {
- final boolean sideStageVisible = mSideStageListener.mVisible;
- final boolean mainStageVisible = mMainStageListener.mVisible;
- final boolean bothStageVisible = sideStageVisible && mainStageVisible;
- final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible;
- final boolean sameVisibility = sideStageVisible == mainStageVisible;
- // Only add or remove divider when both visible or both invisible to avoid sometimes we only
- // got one stage visibility changed for a moment and it will cause flicker.
- if (sameVisibility) {
- setDividerVisibility(bothStageVisible);
- }
-
- if (bothStageInvisible) {
- if (mExitSplitScreenOnHide
- // Don't dismiss staged split when both stages are not visible due to sleeping display,
- // like the cases keyguard showing or screen off.
- || (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping)) {
- exitSplitScreen(null /* childrenToTop */,
- SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
- }
- } else if (mKeyguardOccluded) {
- // At least one of the stages is visible while keyguard occluded. Dismiss split because
- // there's show-when-locked activity showing on top of keyguard. Also make sure the
- // task contains show-when-locked activity remains on top after split dismissed.
- final StageTaskListener toTop =
- mainStageVisible ? mMainStage : (sideStageVisible ? mSideStage : null);
- exitSplitScreen(toTop, SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP);
- }
-
- mSyncQueue.runInSync(t -> {
- // Same above, we only set root tasks and divider leash visibility when both stage
- // change to visible or invisible to avoid flicker.
- if (sameVisibility) {
- t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
- .setVisibility(mMainStage.mRootLeash, bothStageVisible);
- applyDividerVisibility(t);
- applyOutlineVisibility(t);
- }
- });
- }
-
- private void applyDividerVisibility(SurfaceControl.Transaction t) {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) {
- return;
- }
-
- if (mDividerVisible) {
- t.show(dividerLeash)
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left,
- mSplitLayout.getDividerBounds().top);
- } else {
- t.hide(dividerLeash);
- }
- }
-
- private void applyOutlineVisibility(SurfaceControl.Transaction t) {
- final SurfaceControl outlineLeash = mSideStage.getOutlineLeash();
- if (outlineLeash == null) {
- return;
- }
-
- if (mDividerVisible) {
- t.show(outlineLeash).setLayer(outlineLeash, Integer.MAX_VALUE);
- } else {
- t.hide(outlineLeash);
- }
- }
-
- private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
- final boolean hasChildren = stageListener.mHasChildren;
- final boolean isSideStage = stageListener == mSideStageListener;
- if (!hasChildren) {
- if (isSideStage && mMainStageListener.mVisible) {
- // Exit to main stage if side stage no longer has children.
- exitSplitScreen(mMainStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
- } else if (!isSideStage && mSideStageListener.mVisible) {
- // Exit to side stage if main stage no longer has children.
- exitSplitScreen(mSideStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
- }
- } else if (isSideStage) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Make sure the main stage is active.
- mMainStage.activate(getMainStageBounds(), wct);
- mSideStage.setBounds(getSideStageBounds(), wct);
- mTaskOrganizer.applyTransaction(wct);
- }
- if (!mLogger.hasStartedSession() && mMainStageListener.mHasChildren
- && mSideStageListener.mHasChildren) {
- mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
- getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
- }
- }
-
- @VisibleForTesting
- IBinder onSnappedToDismissTransition(boolean mainStageToTop) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE, wct);
- return mSplitTransitions.startSnapToDismiss(wct, this);
- }
-
- @Override
- public void onSnappedToDismiss(boolean bottomOrRight) {
- final boolean mainStageToTop =
- bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
- : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
- if (ENABLE_SHELL_TRANSITIONS) {
- onSnappedToDismissTransition(mainStageToTop);
- return;
- }
- exitSplitScreen(mainStageToTop ? mMainStage : mSideStage,
- SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER);
- }
-
- @Override
- public void onDoubleTappedDivider() {
- setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT, null /* wct */);
- mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
- }
-
- @Override
- public void onLayoutPositionChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t, true /* applyResizingOffset */));
- }
-
- @Override
- public void onLayoutSizeChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t, true /* applyResizingOffset */));
- mSideStage.setOutlineVisibility(false);
- }
-
- @Override
- public void onLayoutSizeChanged(SplitLayout layout) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- updateWindowBounds(layout, wct);
- updateUnfoldBounds();
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t, false /* applyResizingOffset */));
- mSideStage.setOutlineVisibility(true);
- mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
- }
-
- private void updateUnfoldBounds() {
- if (mMainUnfoldController != null && mSideUnfoldController != null) {
- mMainUnfoldController.onLayoutChanged(getMainStageBounds());
- mSideUnfoldController.onLayoutChanged(getSideStageBounds());
- }
- }
-
- /**
- * Populates `wct` with operations that match the split windows to the current layout.
- * To match relevant surfaces, make sure to call updateSurfaceBounds after `wct` is applied
- */
- private void updateWindowBounds(SplitLayout layout, WindowContainerTransaction wct) {
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
- layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo);
- }
-
- void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t,
- boolean applyResizingOffset) {
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
- (layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
- bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer,
- applyResizingOffset);
- }
-
- @Override
- public int getSplitItemPosition(WindowContainerToken token) {
- if (token == null) {
- return SPLIT_POSITION_UNDEFINED;
- }
-
- if (token.equals(mMainStage.mRootTaskInfo.getToken())) {
- return getMainStagePosition();
- } else if (token.equals(mSideStage.mRootTaskInfo.getToken())) {
- return getSideStagePosition();
- }
-
- return SPLIT_POSITION_UNDEFINED;
- }
-
- @Override
- public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
- final StageTaskListener topLeftStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
- final StageTaskListener bottomRightStage =
- mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
- bottomRightStage.mRootTaskInfo);
- mTaskOrganizer.applyTransaction(wct);
- }
-
- @Override
- public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
- mDisplayAreaInfo = displayAreaInfo;
- if (mSplitLayout == null) {
- mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
- mDisplayAreaInfo.configuration, this, mParentContainerCallbacks,
- mDisplayImeController, mTaskOrganizer, SplitLayout.PARALLAX_DISMISSING);
- mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
-
- if (mMainUnfoldController != null && mSideUnfoldController != null) {
- mMainUnfoldController.init();
- mSideUnfoldController.init();
- }
- }
- }
-
- @Override
- public void onDisplayAreaVanished(DisplayAreaInfo displayAreaInfo) {
- throw new IllegalStateException("Well that was unexpected...");
- }
-
- @Override
- public void onDisplayAreaInfoChanged(DisplayAreaInfo displayAreaInfo) {
- mDisplayAreaInfo = displayAreaInfo;
- if (mSplitLayout != null
- && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
- && mMainStage.isActive()) {
- onLayoutSizeChanged(mSplitLayout);
- }
- }
-
- private void onFoldedStateChanged(boolean folded) {
- mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
- if (!folded) return;
-
- if (mMainStage.isFocused()) {
- mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
- } else if (mSideStage.isFocused()) {
- mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
- }
- }
-
- private Rect getSideStageBounds() {
- return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? mSplitLayout.getBounds1() : mSplitLayout.getBounds2();
- }
-
- private Rect getMainStageBounds() {
- return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
- ? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
- }
-
- /**
- * Get the stage that should contain this `taskInfo`. The stage doesn't necessarily contain
- * this task (yet) so this can also be used to identify which stage to put a task into.
- */
- private StageTaskListener getStageOfTask(ActivityManager.RunningTaskInfo taskInfo) {
- // TODO(b/184679596): Find a way to either include task-org information in the transition,
- // or synchronize task-org callbacks so we can use stage.containsTask
- if (mMainStage.mRootTaskInfo != null
- && taskInfo.parentTaskId == mMainStage.mRootTaskInfo.taskId) {
- return mMainStage;
- } else if (mSideStage.mRootTaskInfo != null
- && taskInfo.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
- return mSideStage;
- }
- return null;
- }
-
- @SplitScreen.StageType
- private int getStageType(StageTaskListener stage) {
- return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
- }
-
- @Override
- public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
- @Nullable TransitionRequestInfo request) {
- final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
- if (triggerTask == null) {
- // still want to monitor everything while in split-screen, so return non-null.
- return isSplitScreenVisible() ? new WindowContainerTransaction() : null;
- }
-
- WindowContainerTransaction out = null;
- final @WindowManager.TransitionType int type = request.getType();
- if (isSplitScreenVisible()) {
- // try to handle everything while in split-screen, so return a WCT even if it's empty.
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " split is active so using split"
- + "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
- + " sideChildren=%d", triggerTask.taskId, transitTypeToString(type),
- mMainStage.getChildCount(), mSideStage.getChildCount());
- out = new WindowContainerTransaction();
- final StageTaskListener stage = getStageOfTask(triggerTask);
- if (stage != null) {
- // dismiss split if the last task in one of the stages is going away
- if (isClosingType(type) && stage.getChildCount() == 1) {
- // The top should be the opposite side that is closing:
- mDismissTop = getStageType(stage) == STAGE_TYPE_MAIN
- ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
- }
- } else {
- if (triggerTask.getActivityType() == ACTIVITY_TYPE_HOME && isOpeningType(type)) {
- // Going home so dismiss both.
- mDismissTop = STAGE_TYPE_UNDEFINED;
- }
- }
- if (mDismissTop != NO_DISMISS) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
- + " deduced Dismiss from request. toTop=%s",
- stageTypeToString(mDismissTop));
- prepareExitSplitScreen(mDismissTop, out);
- mSplitTransitions.mPendingDismiss = transition;
- }
- } else {
- // Not in split mode, so look for an open into a split stage just so we can whine and
- // complain about how this isn't a supported operation.
- if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)) {
- if (getStageOfTask(triggerTask) != null) {
- throw new IllegalStateException("Entering split implicitly with only one task"
- + " isn't supported.");
- }
- }
- }
- return out;
- }
-
- @Override
- public boolean startAnimation(@NonNull IBinder transition,
- @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (transition != mSplitTransitions.mPendingDismiss
- && transition != mSplitTransitions.mPendingEnter) {
- // Not entering or exiting, so just do some house-keeping and validation.
-
- // If we're not in split-mode, just abort so something else can handle it.
- if (!isSplitScreenVisible()) return false;
-
- for (int iC = 0; iC < info.getChanges().size(); ++iC) {
- final TransitionInfo.Change change = info.getChanges().get(iC);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo == null || !taskInfo.hasParentTask()) continue;
- final StageTaskListener stage = getStageOfTask(taskInfo);
- if (stage == null) continue;
- if (isOpeningType(change.getMode())) {
- if (!stage.containsTask(taskInfo.taskId)) {
- Log.w(TAG, "Expected onTaskAppeared on " + stage + " to have been called"
- + " with " + taskInfo.taskId + " before startAnimation().");
- }
- } else if (isClosingType(change.getMode())) {
- if (stage.containsTask(taskInfo.taskId)) {
- Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
- + " with " + taskInfo.taskId + " before startAnimation().");
- }
- }
- }
- if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
- // TODO(shell-transitions): Implement a fallback behavior for now.
- throw new IllegalStateException("Somehow removed the last task in a stage"
- + " outside of a proper transition");
- // This can happen in some pathological cases. For example:
- // 1. main has 2 tasks [Task A (Single-task), Task B], side has one task [Task C]
- // 2. Task B closes itself and starts Task A in LAUNCH_ADJACENT at the same time
- // In this case, the result *should* be that we leave split.
- // TODO(b/184679596): Find a way to either include task-org information in
- // the transition, or synchronize task-org callbacks.
- }
-
- // Use normal animations.
- return false;
- }
-
- boolean shouldAnimate = true;
- if (mSplitTransitions.mPendingEnter == transition) {
- shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
- } else if (mSplitTransitions.mPendingDismiss == transition) {
- shouldAnimate = startPendingDismissAnimation(transition, info, startTransaction);
- }
- if (!shouldAnimate) return false;
-
- mSplitTransitions.playAnimation(transition, info, startTransaction, finishTransaction,
- finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
- return true;
- }
-
- private boolean startPendingEnterAnimation(@NonNull IBinder transition,
- @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
- if (info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN) {
- // First, verify that we actually have opened 2 apps in split.
- TransitionInfo.Change mainChild = null;
- TransitionInfo.Change sideChild = null;
- for (int iC = 0; iC < info.getChanges().size(); ++iC) {
- final TransitionInfo.Change change = info.getChanges().get(iC);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo == null || !taskInfo.hasParentTask()) continue;
- final @SplitScreen.StageType int stageType = getStageType(getStageOfTask(taskInfo));
- if (stageType == STAGE_TYPE_MAIN) {
- mainChild = change;
- } else if (stageType == STAGE_TYPE_SIDE) {
- sideChild = change;
- }
- }
- if (mainChild == null || sideChild == null) {
- throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
- + " 2 tasks in transition. Possibly one of them failed to launch");
- // TODO: fallback logic. Probably start a new transition to exit split before
- // applying anything here. Ideally consolidate with transition-merging.
- }
-
- // Update local states (before animating).
- setDividerVisibility(true);
- setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateBounds */,
- null /* wct */);
- setSplitsVisible(true);
-
- addDividerBarToTransition(info, t, true /* show */);
-
- // Make some noise if things aren't totally expected. These states shouldn't effect
- // transitions locally, but remotes (like Launcher) may get confused if they were
- // depending on listener callbacks. This can happen because task-organizer callbacks
- // aren't serialized with transition callbacks.
- // TODO(b/184679596): Find a way to either include task-org information in
- // the transition, or synchronize task-org callbacks.
- if (!mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
- Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
- + " to have been called with " + mainChild.getTaskInfo().taskId
- + " before startAnimation().");
- }
- if (!mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
- Log.w(TAG, "Expected onTaskAppeared on " + mSideStage
- + " to have been called with " + sideChild.getTaskInfo().taskId
- + " before startAnimation().");
- }
- return true;
- } else {
- // TODO: other entry method animations
- throw new RuntimeException("Unsupported split-entry");
- }
- }
-
- private boolean startPendingDismissAnimation(@NonNull IBinder transition,
- @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
- // Make some noise if things aren't totally expected. These states shouldn't effect
- // transitions locally, but remotes (like Launcher) may get confused if they were
- // depending on listener callbacks. This can happen because task-organizer callbacks
- // aren't serialized with transition callbacks.
- // TODO(b/184679596): Find a way to either include task-org information in
- // the transition, or synchronize task-org callbacks.
- if (mMainStage.getChildCount() != 0) {
- final StringBuilder tasksLeft = new StringBuilder();
- for (int i = 0; i < mMainStage.getChildCount(); ++i) {
- tasksLeft.append(i != 0 ? ", " : "");
- tasksLeft.append(mMainStage.mChildrenTaskInfo.keyAt(i));
- }
- Log.w(TAG, "Expected onTaskVanished on " + mMainStage
- + " to have been called with [" + tasksLeft.toString()
- + "] before startAnimation().");
- }
- if (mSideStage.getChildCount() != 0) {
- final StringBuilder tasksLeft = new StringBuilder();
- for (int i = 0; i < mSideStage.getChildCount(); ++i) {
- tasksLeft.append(i != 0 ? ", " : "");
- tasksLeft.append(mSideStage.mChildrenTaskInfo.keyAt(i));
- }
- Log.w(TAG, "Expected onTaskVanished on " + mSideStage
- + " to have been called with [" + tasksLeft.toString()
- + "] before startAnimation().");
- }
-
- // Update local states.
- setSplitsVisible(false);
- // Wait until after animation to update divider
-
- if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
- // Reset crops so they don't interfere with subsequent launches
- t.setWindowCrop(mMainStage.mRootLeash, null);
- t.setWindowCrop(mSideStage.mRootLeash, null);
- }
-
- if (mDismissTop == STAGE_TYPE_UNDEFINED) {
- // Going home (dismissing both splits)
-
- // TODO: Have a proper remote for this. Until then, though, reset state and use the
- // normal animation stuff (which falls back to the normal launcher remote).
- t.hide(mSplitLayout.getDividerLeash());
- setDividerVisibility(false);
- mSplitTransitions.mPendingDismiss = null;
- return false;
- }
-
- addDividerBarToTransition(info, t, false /* show */);
- // We're dismissing split by moving the other one to fullscreen.
- // Since we don't have any animations for this yet, just use the internal example
- // animations.
- return true;
- }
-
- private void addDividerBarToTransition(@NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction t, boolean show) {
- final SurfaceControl leash = mSplitLayout.getDividerLeash();
- final TransitionInfo.Change barChange = new TransitionInfo.Change(null /* token */, leash);
- final Rect bounds = mSplitLayout.getDividerBounds();
- barChange.setStartAbsBounds(bounds);
- barChange.setEndAbsBounds(bounds);
- barChange.setMode(show ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK);
- barChange.setFlags(FLAG_IS_DIVIDER_BAR);
- // Technically this should be order-0, but this is running after layer assignment
- // and it's a special case, so just add to end.
- info.addChange(barChange);
- // Be default, make it visible. The remote animator can adjust alpha if it plans to animate.
- if (show) {
- t.setAlpha(leash, 1.f);
- t.setLayer(leash, Integer.MAX_VALUE);
- t.setPosition(leash, bounds.left, bounds.top);
- t.show(leash);
- }
- }
-
- RemoteAnimationTarget getDividerBarLegacyTarget() {
- final Rect bounds = mSplitLayout.getDividerBounds();
- return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */,
- mSplitLayout.getDividerLeash(), false /* isTranslucent */, null /* clipRect */,
- null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
- new android.graphics.Point(0, 0) /* position */, bounds, bounds,
- new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
- null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
- }
-
- RemoteAnimationTarget getOutlineLegacyTarget() {
- final Rect bounds = mSideStage.mRootTaskInfo.configuration.windowConfiguration.getBounds();
- // Leverage TYPE_DOCK_DIVIDER type when wrapping outline remote animation target in order to
- // distinguish as a split auxiliary target in Launcher.
- return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */,
- mSideStage.getOutlineLeash(), false /* isTranslucent */, null /* clipRect */,
- null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
- new android.graphics.Point(0, 0) /* position */, bounds, bounds,
- new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
- null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + TAG + " mDisplayId=" + mDisplayId);
- pw.println(innerPrefix + "mDividerVisible=" + mDividerVisible);
- pw.println(innerPrefix + "MainStage");
- pw.println(childPrefix + "isActive=" + mMainStage.isActive());
- mMainStageListener.dump(pw, childPrefix);
- pw.println(innerPrefix + "SideStage");
- mSideStageListener.dump(pw, childPrefix);
- pw.println(innerPrefix + "mSplitLayout=" + mSplitLayout);
- }
-
- /**
- * Directly set the visibility of both splits. This assumes hasChildren matches visibility.
- * This is intended for batch use, so it assumes other state management logic is already
- * handled.
- */
- private void setSplitsVisible(boolean visible) {
- mMainStageListener.mVisible = mSideStageListener.mVisible = visible;
- mMainStageListener.mHasChildren = mSideStageListener.mHasChildren = visible;
- }
-
- /**
- * Sets drag info to be logged when splitscreen is next entered.
- */
- public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
- mLogger.enterRequestedByDrag(position, dragSessionId);
- }
-
- /**
- * Logs the exit of splitscreen.
- */
- private void logExit(int exitReason) {
- mLogger.logExit(exitReason,
- SPLIT_POSITION_UNDEFINED, 0 /* mainStageUid */,
- SPLIT_POSITION_UNDEFINED, 0 /* sideStageUid */,
- mSplitLayout.isLandscape());
- }
-
- /**
- * Logs the exit of splitscreen to a specific stage. This must be called before the exit is
- * executed.
- */
- private void logExitToStage(int exitReason, boolean toMainStage) {
- mLogger.logExit(exitReason,
- toMainStage ? getMainStagePosition() : SPLIT_POSITION_UNDEFINED,
- toMainStage ? mMainStage.getTopChildTaskUid() : 0 /* mainStageUid */,
- !toMainStage ? getSideStagePosition() : SPLIT_POSITION_UNDEFINED,
- !toMainStage ? mSideStage.getTopChildTaskUid() : 0 /* sideStageUid */,
- mSplitLayout.isLandscape());
- }
-
- class StageListenerImpl implements StageTaskListener.StageListenerCallbacks {
- boolean mHasRootTask = false;
- boolean mVisible = false;
- boolean mHasChildren = false;
-
- @Override
- public void onRootTaskAppeared() {
- mHasRootTask = true;
- StageCoordinator.this.onStageRootTaskAppeared(this);
- }
-
- @Override
- public void onStatusChanged(boolean visible, boolean hasChildren) {
- if (!mHasRootTask) return;
-
- if (mHasChildren != hasChildren) {
- mHasChildren = hasChildren;
- StageCoordinator.this.onStageHasChildrenChanged(this);
- }
- if (mVisible != visible) {
- mVisible = visible;
- StageCoordinator.this.onStageVisibilityChanged(this);
- }
- }
-
- @Override
- public void onChildTaskStatusChanged(int taskId, boolean present, boolean visible) {
- StageCoordinator.this.onStageChildTaskStatusChanged(this, taskId, present, visible);
- }
-
- @Override
- public void onRootTaskVanished() {
- reset();
- StageCoordinator.this.onStageRootTaskVanished(this);
- }
-
- @Override
- public void onNoLongerSupportMultiWindow() {
- if (mMainStage.isActive()) {
- StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
- SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW);
- }
- }
-
- private void reset() {
- mHasRootTask = false;
- mVisible = false;
- mHasChildren = false;
- }
-
- public void dump(@NonNull PrintWriter pw, String prefix) {
- pw.println(prefix + "mHasRootTask=" + mHasRootTask);
- pw.println(prefix + "mVisible=" + mVisible);
- pw.println(prefix + "mHasChildren=" + mHasChildren);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java
deleted file mode 100644
index 7b679580fa87..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java
+++ /dev/null
@@ -1,298 +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.stagesplit;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
-
-import android.annotation.CallSuper;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.SparseArray;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SurfaceUtils;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import java.io.PrintWriter;
-
-/**
- * Base class that handle common task org. related for split-screen stages.
- * Note that this class and its sub-class do not directly perform hierarchy operations.
- * They only serve to hold a collection of tasks and provide APIs like
- * {@link #setBounds(Rect, WindowContainerTransaction)} for the centralized {@link StageCoordinator}
- * to perform operations in-sync with other containers.
- *
- * @see StageCoordinator
- */
-class StageTaskListener implements ShellTaskOrganizer.TaskListener {
- private static final String TAG = StageTaskListener.class.getSimpleName();
-
- protected static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD};
- protected static final int[] CONTROLLED_WINDOWING_MODES =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
- protected static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
-
- /** Callback interface for listening to changes in a split-screen stage. */
- public interface StageListenerCallbacks {
- void onRootTaskAppeared();
-
- void onStatusChanged(boolean visible, boolean hasChildren);
-
- void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
-
- void onRootTaskVanished();
- void onNoLongerSupportMultiWindow();
- }
-
- private final StageListenerCallbacks mCallbacks;
- private final SurfaceSession mSurfaceSession;
- protected final SyncTransactionQueue mSyncQueue;
-
- protected ActivityManager.RunningTaskInfo mRootTaskInfo;
- protected SurfaceControl mRootLeash;
- protected SurfaceControl mDimLayer;
- protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>();
- private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>();
-
- private final StageTaskUnfoldController mStageTaskUnfoldController;
-
- StageTaskListener(ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
- @Nullable StageTaskUnfoldController stageTaskUnfoldController) {
- mCallbacks = callbacks;
- mSyncQueue = syncQueue;
- mSurfaceSession = surfaceSession;
- mStageTaskUnfoldController = stageTaskUnfoldController;
- taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
- }
-
- int getChildCount() {
- return mChildrenTaskInfo.size();
- }
-
- boolean containsTask(int taskId) {
- return mChildrenTaskInfo.contains(taskId);
- }
-
- /**
- * Returns the top activity uid for the top child task.
- */
- int getTopChildTaskUid() {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
- if (info.topActivityInfo == null) {
- continue;
- }
- return info.topActivityInfo.applicationInfo.uid;
- }
- return 0;
- }
-
- /** @return {@code true} if this listener contains the currently focused task. */
- boolean isFocused() {
- 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;
- }
-
- @Override
- @CallSuper
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mRootTaskInfo == null && !taskInfo.hasParentTask()) {
- mRootLeash = leash;
- mRootTaskInfo = taskInfo;
- mCallbacks.onRootTaskAppeared();
- sendStatusChanged();
- mSyncQueue.runInSync(t -> {
- t.hide(mRootLeash);
- mDimLayer =
- SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession);
- });
- } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
- final int taskId = taskInfo.taskId;
- mChildrenLeashes.put(taskId, leash);
- mChildrenTaskInfo.put(taskId, taskInfo);
- updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
- mCallbacks.onChildTaskStatusChanged(taskId, true /* present */, taskInfo.isVisible);
- if (ENABLE_SHELL_TRANSITIONS) {
- // Status is managed/synchronized by the transition lifecycle.
- return;
- }
- sendStatusChanged();
- } else {
- throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
- + "\n mRootTaskInfo: " + mRootTaskInfo);
- }
-
- if (mStageTaskUnfoldController != null) {
- mStageTaskUnfoldController.onTaskAppeared(taskInfo, leash);
- }
- }
-
- @Override
- @CallSuper
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (!taskInfo.supportsMultiWindow) {
- // Leave split screen if the task no longer supports multi window.
- mCallbacks.onNoLongerSupportMultiWindow();
- return;
- }
- if (mRootTaskInfo.taskId == taskInfo.taskId) {
- mRootTaskInfo = taskInfo;
- } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
- mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
- mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
- taskInfo.isVisible);
- if (!ENABLE_SHELL_TRANSITIONS) {
- updateChildTaskSurface(
- taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
- }
- } else {
- throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
- + "\n mRootTaskInfo: " + mRootTaskInfo);
- }
- if (ENABLE_SHELL_TRANSITIONS) {
- // Status is managed/synchronized by the transition lifecycle.
- return;
- }
- sendStatusChanged();
- }
-
- @Override
- @CallSuper
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskId = taskInfo.taskId;
- if (mRootTaskInfo.taskId == taskId) {
- mCallbacks.onRootTaskVanished();
- mSyncQueue.runInSync(t -> t.remove(mDimLayer));
- mRootTaskInfo = null;
- } else if (mChildrenTaskInfo.contains(taskId)) {
- mChildrenTaskInfo.remove(taskId);
- mChildrenLeashes.remove(taskId);
- mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
- if (ENABLE_SHELL_TRANSITIONS) {
- // Status is managed/synchronized by the transition lifecycle.
- return;
- }
- sendStatusChanged();
- } else {
- throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
- + "\n mRootTaskInfo: " + mRootTaskInfo);
- }
-
- if (mStageTaskUnfoldController != null) {
- mStageTaskUnfoldController.onTaskVanished(taskInfo);
- }
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- b.setParent(findTaskSurface(taskId));
- }
-
- @Override
- public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
- SurfaceControl.Transaction t) {
- t.reparent(sc, findTaskSurface(taskId));
- }
-
- private SurfaceControl findTaskSurface(int taskId) {
- if (mRootTaskInfo.taskId == taskId) {
- return mRootLeash;
- } else if (mChildrenLeashes.contains(taskId)) {
- return mChildrenLeashes.get(taskId);
- } else {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- }
-
- void setBounds(Rect bounds, WindowContainerTransaction wct) {
- wct.setBounds(mRootTaskInfo.token, bounds);
- }
-
- void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) {
- if (!containsTask(taskId)) {
- return;
- }
- wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */);
- }
-
- void setVisibility(boolean visible, WindowContainerTransaction wct) {
- wct.reorder(mRootTaskInfo.token, visible /* onTop */);
- }
-
- void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener,
- @SplitScreen.StageType int stage) {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- int taskId = mChildrenTaskInfo.keyAt(i);
- listener.onTaskStageChanged(taskId, stage,
- mChildrenTaskInfo.get(taskId).isVisible);
- }
- }
-
- private void updateChildTaskSurface(ActivityManager.RunningTaskInfo taskInfo,
- SurfaceControl leash, boolean firstAppeared) {
- final Point taskPositionInParent = taskInfo.positionInParent;
- mSyncQueue.runInSync(t -> {
- t.setWindowCrop(leash, null);
- t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
- if (firstAppeared && !ENABLE_SHELL_TRANSITIONS) {
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- }
- });
- }
-
- private void sendStatusChanged() {
- mCallbacks.onStatusChanged(mRootTaskInfo.isVisible, mChildrenTaskInfo.size() > 0);
- }
-
- @Override
- @CallSuper
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- final String childPrefix = innerPrefix + " ";
- pw.println(prefix + this);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskUnfoldController.java
deleted file mode 100644
index 62b9da6d4715..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskUnfoldController.java
+++ /dev/null
@@ -1,224 +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.stagesplit;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.animation.RectEvaluator;
-import android.animation.TypeEvaluator;
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.SparseArray;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
-import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
-import com.android.wm.shell.unfold.UnfoldBackgroundController;
-
-import java.util.concurrent.Executor;
-
-/**
- * Controls transformations of the split screen task surfaces in response
- * to the unfolding/folding action on foldable devices
- */
-public class StageTaskUnfoldController implements UnfoldListener, OnInsetsChangedListener {
-
- private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect());
- private static final float CROPPING_START_MARGIN_FRACTION = 0.05f;
-
- private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
- private final ShellUnfoldProgressProvider mUnfoldProgressProvider;
- private final DisplayInsetsController mDisplayInsetsController;
- private final UnfoldBackgroundController mBackgroundController;
- private final Executor mExecutor;
- private final int mExpandedTaskBarHeight;
- private final float mWindowCornerRadiusPx;
- private final Rect mStageBounds = new Rect();
- private final TransactionPool mTransactionPool;
-
- private InsetsSource mTaskbarInsetsSource;
- private boolean mBothStagesVisible;
-
- public StageTaskUnfoldController(@NonNull Context context,
- @NonNull TransactionPool transactionPool,
- @NonNull ShellUnfoldProgressProvider unfoldProgressProvider,
- @NonNull DisplayInsetsController displayInsetsController,
- @NonNull UnfoldBackgroundController backgroundController,
- @NonNull Executor executor) {
- mUnfoldProgressProvider = unfoldProgressProvider;
- mTransactionPool = transactionPool;
- mExecutor = executor;
- mBackgroundController = backgroundController;
- mDisplayInsetsController = displayInsetsController;
- mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.taskbar_frame_height);
- }
-
- /**
- * Initializes the controller, starts listening for the external events
- */
- public void init() {
- mUnfoldProgressProvider.addListener(mExecutor, this);
- mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this);
- }
-
- @Override
- public void insetsChanged(InsetsState insetsState) {
- mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- AnimationContext context = mAnimationContextByTaskId.valueAt(i);
- context.update();
- }
- }
-
- /**
- * Called when split screen task appeared
- * @param taskInfo info for the appeared task
- * @param leash surface leash for the appeared task
- */
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- AnimationContext context = new AnimationContext(leash);
- mAnimationContextByTaskId.put(taskInfo.taskId, context);
- }
-
- /**
- * Called when a split screen task vanished
- * @param taskInfo info for the vanished task
- */
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId);
- if (context != null) {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- resetSurface(transaction, context);
- transaction.apply();
- mTransactionPool.release(transaction);
- }
- mAnimationContextByTaskId.remove(taskInfo.taskId);
- }
-
- @Override
- public void onStateChangeProgress(float progress) {
- if (mAnimationContextByTaskId.size() == 0 || !mBothStagesVisible) return;
-
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- mBackgroundController.ensureBackground(transaction);
-
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- AnimationContext context = mAnimationContextByTaskId.valueAt(i);
-
- context.mCurrentCropRect.set(RECT_EVALUATOR
- .evaluate(progress, context.mStartCropRect, context.mEndCropRect));
-
- transaction.setWindowCrop(context.mLeash, context.mCurrentCropRect)
- .setCornerRadius(context.mLeash, mWindowCornerRadiusPx);
- }
-
- transaction.apply();
-
- mTransactionPool.release(transaction);
- }
-
- @Override
- public void onStateChangeFinished() {
- resetTransformations();
- }
-
- /**
- * Called when split screen visibility changes
- * @param bothStagesVisible true if both stages of the split screen are visible
- */
- public void onSplitVisibilityChanged(boolean bothStagesVisible) {
- mBothStagesVisible = bothStagesVisible;
- if (!bothStagesVisible) {
- resetTransformations();
- }
- }
-
- /**
- * Called when split screen stage bounds changed
- * @param bounds new bounds for this stage
- */
- public void onLayoutChanged(Rect bounds) {
- mStageBounds.set(bounds);
-
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
- context.update();
- }
- }
-
- private void resetTransformations() {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
-
- for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
- final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
- resetSurface(transaction, context);
- }
- mBackgroundController.removeBackground(transaction);
- transaction.apply();
-
- mTransactionPool.release(transaction);
- }
-
- private void resetSurface(SurfaceControl.Transaction transaction, AnimationContext context) {
- transaction
- .setWindowCrop(context.mLeash, null)
- .setCornerRadius(context.mLeash, 0.0F);
- }
-
- private class AnimationContext {
- final SurfaceControl mLeash;
- final Rect mStartCropRect = new Rect();
- final Rect mEndCropRect = new Rect();
- final Rect mCurrentCropRect = new Rect();
-
- private AnimationContext(SurfaceControl leash) {
- this.mLeash = leash;
- update();
- }
-
- private void update() {
- mStartCropRect.set(mStageBounds);
-
- if (mTaskbarInsetsSource != null) {
- // Only insets the cropping window with taskbar when taskbar is expanded
- if (mTaskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
- mStartCropRect.inset(mTaskbarInsetsSource
- .calculateVisibleInsets(mStartCropRect));
- }
- }
-
- // Offset to surface coordinates as layout bounds are in screen coordinates
- mStartCropRect.offsetTo(0, 0);
-
- mEndCropRect.set(mStartCropRect);
-
- int maxSize = Math.max(mEndCropRect.width(), mEndCropRect.height());
- int margin = (int) (maxSize * CROPPING_START_MARGIN_FRACTION);
- mStartCropRect.inset(margin, margin, margin, margin);
- }
- }
-}
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 54d62edf2570..a0e176c7ea68 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
@@ -261,7 +261,8 @@ public class StartingSurfaceDrawer {
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.setFitInsetsSides(0);
params.setFitInsetsTypes(0);
- params.format = PixelFormat.TRANSLUCENT;
+ params.format = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+ ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
new file mode 100644
index 000000000000..1ffe26df729f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2022 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.transition;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
+import static com.android.wm.shell.splitscreen.StageCoordinator.FLAG_IS_DIVIDER_BAR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.StageCoordinator;
+
+import java.util.ArrayList;
+
+/**
+ * A handler for dealing with transitions involving multiple other handlers. For example: an
+ * activity in split-screen going into PiP.
+ */
+public class DefaultMixedHandler implements Transitions.TransitionHandler {
+
+ private final Transitions mPlayer;
+ private final PipTransitionController mPipHandler;
+ private final StageCoordinator mSplitHandler;
+
+ private static class MixedTransition {
+ static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
+
+ final int mType;
+ final IBinder mTransition;
+
+ Transitions.TransitionFinishCallback mFinishCallback = null;
+
+ /**
+ * Mixed transitions are made up of multiple "parts". This keeps track of how many
+ * parts are currently animating.
+ */
+ int mInFlightSubAnimations = 0;
+
+ MixedTransition(int type, IBinder transition) {
+ mType = type;
+ mTransition = transition;
+ }
+ }
+ private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
+
+ public DefaultMixedHandler(@NonNull Transitions player,
+ @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ mPlayer = player;
+ mPipHandler = pipHandler;
+ mSplitHandler = splitHandler;
+ }
+
+ @Nullable
+ @Override
+ public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request) {
+ if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
+ + "Split-Screen is active, so treat it as Mixed.");
+ if (request.getRemoteTransition() != null) {
+ throw new IllegalStateException("Unexpected remote transition in"
+ + "pip-enter-from-split request");
+ }
+ mActiveTransitions.add(new MixedTransition(MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT,
+ transition));
+
+ WindowContainerTransaction out = new WindowContainerTransaction();
+ mPipHandler.augmentRequest(transition, request, out);
+ mSplitHandler.addEnterOrExitIfNeeded(request, out);
+ return out;
+ }
+ return null;
+ }
+
+ private TransitionInfo subCopy(@NonNull TransitionInfo info,
+ @WindowManager.TransitionType int newType) {
+ final TransitionInfo out = new TransitionInfo(newType, info.getFlags());
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ out.getChanges().add(info.getChanges().get(i));
+ }
+ out.setRootLeash(info.getRootLeash(), info.getRootOffset().x, info.getRootOffset().y);
+ out.setAnimationOptions(info.getAnimationOptions());
+ return out;
+ }
+
+ private boolean isHomeOpening(@NonNull TransitionInfo.Change change) {
+ return change.getTaskInfo() != null
+ && change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME;
+ }
+
+ private boolean isWallpaper(@NonNull TransitionInfo.Change change) {
+ return (change.getFlags() & FLAG_IS_WALLPAPER) != 0;
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ MixedTransition mixed = null;
+ for (int i = mActiveTransitions.size() - 1; i >= 0; --i) {
+ if (mActiveTransitions.get(i).mTransition != transition) continue;
+ mixed = mActiveTransitions.remove(i);
+ break;
+ }
+ if (mixed == null) return false;
+
+ if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
+ return animateEnterPipFromSplit(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
+ } else {
+ throw new IllegalStateException("Starting mixed animation without a known mixed type? "
+ + mixed.mType);
+ }
+ }
+
+ private boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for "
+ + "entering PIP while Split-Screen is active.");
+ TransitionInfo.Change pipChange = null;
+ TransitionInfo.Change wallpaper = null;
+ final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK);
+ boolean homeIsOpening = false;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (mPipHandler.isEnteringPip(change, info.getType())) {
+ if (pipChange != null) {
+ throw new IllegalStateException("More than 1 pip-entering changes in one"
+ + " transition? " + info);
+ }
+ pipChange = change;
+ // going backwards, so remove-by-index is fine.
+ everythingElse.getChanges().remove(i);
+ } else if (isHomeOpening(change)) {
+ homeIsOpening = true;
+ } else if (isWallpaper(change)) {
+ wallpaper = change;
+ }
+ }
+ if (pipChange == null) {
+ // um, something probably went wrong.
+ return false;
+ }
+ final boolean isGoingHome = homeIsOpening;
+ mixed.mFinishCallback = finishCallback;
+ Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ --mixed.mInFlightSubAnimations;
+ if (mixed.mInFlightSubAnimations > 0) return;
+ if (isGoingHome) {
+ mSplitHandler.onTransitionAnimationComplete();
+ }
+ mixed.mFinishCallback.onTransitionFinished(wct, wctCB);
+ };
+ if (isGoingHome) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
+ + "since entering-PiP caused us to leave split and return home.");
+ // We need to split the transition into 2 parts: the pip part (animated by pip)
+ // and the dismiss-part (animated by launcher).
+ mixed.mInFlightSubAnimations = 2;
+ // immediately make the wallpaper visible (so that we don't see it pop-in during
+ // the time it takes to start recents animation (which is remote).
+ if (wallpaper != null) {
+ startTransaction.show(wallpaper.getLeash()).setAlpha(wallpaper.getLeash(), 1.f);
+ }
+ // make a new startTransaction because pip's startEnterAnimation "consumes" it so
+ // we need a separate one to send over to launcher.
+ SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
+ // Let split update internal state for dismiss.
+ mSplitHandler.prepareDismissAnimation(STAGE_TYPE_UNDEFINED,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
+ finishTransaction);
+
+ // We are trying to accommodate launcher's close animation which can't handle the
+ // divider-bar, so if split-handler is closing the divider-bar, just hide it and remove
+ // from transition info.
+ for (int i = everythingElse.getChanges().size() - 1; i >= 0; --i) {
+ if ((everythingElse.getChanges().get(i).getFlags() & FLAG_IS_DIVIDER_BAR) != 0) {
+ everythingElse.getChanges().remove(i);
+ break;
+ }
+ }
+
+ mPipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction,
+ finishCB);
+ // Dispatch the rest of the transition normally. This will most-likely be taken by
+ // recents or default handler.
+ mPlayer.dispatchTransition(mixed.mTransition, everythingElse, otherStartT,
+ finishTransaction, finishCB, this);
+ } else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Not leaving split, so just "
+ + "forward animation to Pip-Handler.");
+ // This happens if the pip-ing activity is in a multi-activity task (and thus a
+ // new pip task is spawned). In this case, we don't actually exit split so we can
+ // just let pip transition handle the animation verbatim.
+ mixed.mInFlightSubAnimations = 1;
+ mPipHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction,
+ finishCB);
+ }
+ return true;
+ }
+
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ }
+
+ @Override
+ public void onTransitionMerged(@NonNull IBinder transition) {
+ MixedTransition mixed = null;
+ for (int i = mActiveTransitions.size() - 1; i >= 0; --i) {
+ if (mActiveTransitions.get(i).mTransition != transition) continue;
+ mixed = mActiveTransitions.remove(i);
+ break;
+ }
+ if (mixed == null) return;
+ if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
+ mPipHandler.onTransitionMerged(transition);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 9154226b7b22..79e9cda3c389 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -24,6 +24,7 @@ import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -42,6 +43,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
@@ -684,6 +686,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final Rect endBounds = Transitions.isClosingType(changeMode)
? mRotator.getEndBoundsInStartRotation(change)
: change.getEndAbsBounds();
+ final boolean isDream =
+ isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
if (info.isKeyguardGoingAway()) {
a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
@@ -726,7 +730,17 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
} else {
int animAttr = 0;
boolean translucent = false;
- if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+ if (isDream) {
+ if (type == TRANSIT_OPEN) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
+ : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
+ } else if (type == TRANSIT_CLOSE) {
+ animAttr = enter
+ ? 0
+ : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
+ }
+ } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
animAttr = enter
? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
: R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
@@ -790,6 +804,11 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
}
}
+
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
+ transitTypeToString(type),
+ enter);
}
if (a != null) {
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 435d67087f34..de0f47fa0a6b 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
@@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -287,12 +288,14 @@ public class Transitions implements RemoteCallable<Transitions> {
finishT.setAlpha(leash, 1.f);
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
- // Wallpaper is a bit of an anomaly: it's visibility is tied to other WindowStates.
- // As a result, we actually can't hide it's WindowToken because there may not be a
- // transition associated with it becoming visible again. Fortunately, since it is
- // always z-ordered to the back, we don't have to worry about it flickering to the
- // front during reparenting, so the hide here isn't necessary for it.
- if ((change.getFlags() & FLAG_IS_WALLPAPER) == 0) {
+ // Wallpaper/IME are anomalies: their visibility is tied to other WindowStates.
+ // As a result, we actually can't hide their WindowTokens because there may not be a
+ // transition associated with them becoming visible again. Fortunately, since
+ // wallpapers are always z-ordered to the back, we don't have to worry about it
+ // flickering to the front during reparenting. Similarly, the IME is reparented to
+ // the associated app, so its visibility is coupled. So, an explicit hide is not
+ // needed visually anyways.
+ if ((change.getFlags() & (FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD)) == 0) {
finishT.hide(leash);
}
}
@@ -309,13 +312,14 @@ public class Transitions implements RemoteCallable<Transitions> {
if (info.getRootLeash().isValid()) {
t.show(info.getRootLeash());
}
+ final int numChanges = info.getChanges().size();
// Put animating stuff above this line and put static stuff below it.
- int zSplitLine = info.getChanges().size();
+ final int zSplitLine = numChanges + 1;
// changes should be ordered top-to-bottom in z
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ for (int i = numChanges - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = change.getLeash();
- final int mode = info.getChanges().get(i).getMode();
+ final int mode = change.getMode();
// Don't reparent anything that isn't independent within its parents
if (!TransitionInfo.isIndependent(change, info)) {
@@ -329,26 +333,31 @@ public class Transitions implements RemoteCallable<Transitions> {
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
change.getStartAbsBounds().top - info.getRootOffset().y);
}
+ final int layer;
// Put all the OPEN/SHOW on top
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+ // Wallpaper is always at the bottom.
+ layer = 0;
+ } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
// put on top
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
} else {
// put on bottom
- t.setLayer(leash, zSplitLine - i);
+ layer = zSplitLine - i;
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
if (isOpening) {
// put on bottom and leave visible
- t.setLayer(leash, zSplitLine - i);
+ layer = zSplitLine - i;
} else {
// put on top
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
}
} else { // CHANGE or other
- t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
+ layer = zSplitLine + numChanges - i;
}
+ t.setLayer(leash, layer);
}
}
@@ -377,6 +386,7 @@ public class Transitions implements RemoteCallable<Transitions> {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Invalid root leash (%s): %s",
transitionToken, info);
t.apply();
+ finishT.apply();
onAbort(transitionToken);
return;
}
@@ -400,6 +410,7 @@ public class Transitions implements RemoteCallable<Transitions> {
}
if (nonTaskChange && transferStartingWindow) {
t.apply();
+ finishT.apply();
// Treat this as an abort since we are bypassing any merge logic and effectively
// finishing immediately.
onAbort(transitionToken);
@@ -435,33 +446,42 @@ public class Transitions implements RemoteCallable<Transitions> {
playing.mToken, (wct, cb) -> onFinish(merging.mToken, wct, cb));
}
- boolean startAnimation(@NonNull ActiveTransition active, TransitionHandler handler) {
- return handler.startAnimation(active.mToken, active.mInfo, active.mStartT, active.mFinishT,
- (wct, cb) -> onFinish(active.mToken, wct, cb));
- }
-
- void playTransition(@NonNull ActiveTransition active) {
+ private void playTransition(@NonNull ActiveTransition active) {
setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT);
// If a handler already chose to run this animation, try delegating to it first.
if (active.mHandler != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try firstHandler %s",
active.mHandler);
- if (startAnimation(active, active.mHandler)) {
+ boolean consumed = active.mHandler.startAnimation(active.mToken, active.mInfo,
+ active.mStartT, active.mFinishT, (wct, cb) -> onFinish(active.mToken, wct, cb));
+ if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by firstHandler");
return;
}
}
- // Otherwise give every other handler a chance (in order)
+ // Otherwise give every other handler a chance
+ active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
+ active.mFinishT, (wct, cb) -> onFinish(active.mToken, wct, cb), active.mHandler);
+ }
+
+ /**
+ * Gives every handler (in order) a chance to animate until one consumes the transition.
+ * @return the handler which consumed the transition.
+ */
+ TransitionHandler dispatchTransition(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT,
+ @NonNull TransitionFinishCallback finishCB, @Nullable TransitionHandler skip) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
- if (mHandlers.get(i) == active.mHandler) continue;
+ if (mHandlers.get(i) == skip) continue;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try handler %s",
mHandlers.get(i));
- if (startAnimation(active, mHandlers.get(i))) {
+ boolean consumed = mHandlers.get(i).startAnimation(transition, info, startT, finishT,
+ finishCB);
+ if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by %s",
mHandlers.get(i));
- active.mHandler = mHandlers.get(i);
- return;
+ return mHandlers.get(i);
}
}
throw new IllegalStateException(
@@ -615,8 +635,9 @@ public class Transitions implements RemoteCallable<Transitions> {
if (wct == null) {
wct = new WindowContainerTransaction();
}
- mDisplayController.getChangeController().dispatchOnRotateDisplay(wct,
- change.getDisplayId(), change.getStartRotation(), change.getEndRotation());
+ mDisplayController.getChangeController().dispatchOnDisplayChange(wct,
+ change.getDisplayId(), change.getStartRotation(), change.getEndRotation(),
+ null /* newDisplayAreaInfo */);
}
}
active.mToken = mOrganizer.startTransition(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
index 9faf454261d3..86ca292399cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
@@ -79,7 +79,7 @@ public class UnfoldBackgroundController {
}
private float[] getBackgroundColor(Context context) {
- int colorInt = context.getResources().getColor(R.color.unfold_transition_background);
+ int colorInt = context.getResources().getColor(R.color.taskbar_background);
return new float[]{
(float) red(colorInt) / 255.0F,
(float) green(colorInt) / 255.0F,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 639603941c18..8e45e7d36b86 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -34,15 +34,20 @@ import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
import com.android.wm.shell.transition.Transitions.TransitionHandler;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
+import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.Executor;
+/**
+ * Transition handler that is responsible for animating app surfaces when unfolding of foldable
+ * devices. It does not handle the folding animation, which is done in
+ * {@link com.android.wm.shell.fullscreen.FullscreenUnfoldController}.
+ */
public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListener {
private final ShellUnfoldProgressProvider mUnfoldProgressProvider;
private final Transitions mTransitions;
+ private final UnfoldBackgroundController mUnfoldBackgroundController;
private final Executor mExecutor;
private final TransactionPool mTransactionPool;
@@ -51,17 +56,22 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
@Nullable
private IBinder mTransition;
- private final List<TransitionInfo.Change> mAnimatedFullscreenTasks = new ArrayList<>();
+ private final FullscreenUnfoldTaskAnimator mFullscreenAnimator;
public UnfoldTransitionHandler(ShellUnfoldProgressProvider unfoldProgressProvider,
- TransactionPool transactionPool, Executor executor, Transitions transitions) {
+ FullscreenUnfoldTaskAnimator animator, TransactionPool transactionPool,
+ UnfoldBackgroundController unfoldBackgroundController,
+ Executor executor, Transitions transitions) {
mUnfoldProgressProvider = unfoldProgressProvider;
+ mFullscreenAnimator = animator;
mTransactionPool = transactionPool;
+ mUnfoldBackgroundController = unfoldBackgroundController;
mExecutor = executor;
mTransitions = transitions;
}
public void init() {
+ mFullscreenAnimator.init();
mTransitions.addHandler(this);
mUnfoldProgressProvider.addListener(mExecutor, this);
}
@@ -71,40 +81,36 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull TransitionFinishCallback finishCallback) {
-
if (transition != mTransition) return false;
+ mUnfoldBackgroundController.ensureBackground(startTransaction);
startTransaction.apply();
- mAnimatedFullscreenTasks.clear();
+ mFullscreenAnimator.clearTasks();
info.getChanges().forEach(change -> {
final boolean allowedToAnimate = change.getTaskInfo() != null
+ && change.getTaskInfo().isVisible()
&& change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME
&& change.getMode() == TRANSIT_CHANGE;
if (allowedToAnimate) {
- mAnimatedFullscreenTasks.add(change);
+ mFullscreenAnimator.addTask(change.getTaskInfo(), change.getLeash());
}
});
+ mFullscreenAnimator.resetAllSurfaces(finishTransaction);
+ mUnfoldBackgroundController.removeBackground(finishTransaction);
mFinishCallback = finishCallback;
- mTransition = null;
return true;
}
@Override
public void onStateChangeProgress(float progress) {
- mAnimatedFullscreenTasks.forEach(change -> {
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
-
- // TODO: this is a placeholder animation, replace with a spec version in the next CLs
- final float testScale = 0.8f + 0.2f * progress;
- transaction.setScale(change.getLeash(), testScale, testScale);
-
- transaction.apply();
- mTransactionPool.release(transaction);
- });
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ mFullscreenAnimator.applyAnimationProgress(progress, transaction);
+ transaction.apply();
+ mTransactionPool.release(transaction);
}
@Override
@@ -112,7 +118,8 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(null, null);
mFinishCallback = null;
- mAnimatedFullscreenTasks.clear();
+ mTransition = null;
+ mFullscreenAnimator.clearTasks();
}
}
@@ -127,4 +134,8 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
}
return null;
}
+
+ public boolean willHandleTransition() {
+ return mTransition != null;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
new file mode 100644
index 000000000000..6ec5512c22ec
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 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.unfold.animation;
+
+import static android.util.MathUtils.lerp;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.animation.RectEvaluator;
+import android.animation.TypeEvaluator;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.wm.shell.common.DisplayInsetsController;
+
+/**
+ * This helper class contains logic that calculates scaling and cropping parameters
+ * for the folding/unfolding animation. As an input it receives TaskInfo objects and
+ * surfaces leashes and as an output it could fill surface transactions with required
+ * transformations.
+ *
+ * This class is used by
+ * {@link com.android.wm.shell.unfold.UnfoldTransitionHandler} and
+ * {@link com.android.wm.shell.fullscreen.FullscreenUnfoldController}. They use independent
+ * instances of FullscreenUnfoldTaskAnimator.
+ */
+public class FullscreenUnfoldTaskAnimator implements
+ DisplayInsetsController.OnInsetsChangedListener {
+
+ private static final float[] FLOAT_9 = new float[9];
+ private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+ private static final float HORIZONTAL_START_MARGIN = 0.08f;
+ private static final float VERTICAL_START_MARGIN = 0.03f;
+ private static final float END_SCALE = 1f;
+ private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2;
+
+ private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
+ private final int mExpandedTaskBarHeight;
+ private final float mWindowCornerRadiusPx;
+ private final DisplayInsetsController mDisplayInsetsController;
+
+ private InsetsSource mTaskbarInsetsSource;
+
+ public FullscreenUnfoldTaskAnimator(Context context,
+ DisplayInsetsController displayInsetsController) {
+ mDisplayInsetsController = displayInsetsController;
+ mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.taskbar_frame_height);
+ mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
+ }
+
+ public void init() {
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this);
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+ context.update(mTaskbarInsetsSource, context.mTaskInfo);
+ }
+ }
+
+ public boolean hasActiveTasks() {
+ return mAnimationContextByTaskId.size() > 0;
+ }
+
+ public void addTask(TaskInfo taskInfo, SurfaceControl leash) {
+ AnimationContext animationContext = new AnimationContext(leash, mTaskbarInsetsSource,
+ taskInfo);
+ mAnimationContextByTaskId.put(taskInfo.taskId, animationContext);
+ }
+
+ public void onTaskInfoChanged(TaskInfo taskInfo) {
+ AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
+ if (animationContext != null) {
+ animationContext.update(mTaskbarInsetsSource, taskInfo);
+ }
+ }
+
+ public void removeTask(TaskInfo taskInfo) {
+ mAnimationContextByTaskId.remove(taskInfo.taskId);
+ }
+
+ public void clearTasks() {
+ mAnimationContextByTaskId.clear();
+ }
+
+ public void resetSurface(TaskInfo taskInfo, Transaction transaction) {
+ final AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId);
+ if (context != null) {
+ resetSurface(context, transaction);
+ }
+ }
+
+ public void applyAnimationProgress(float progress, Transaction transaction) {
+ if (mAnimationContextByTaskId.size() == 0) return;
+
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+
+ context.mCurrentCropRect.set(RECT_EVALUATOR
+ .evaluate(progress, context.mStartCropRect, context.mEndCropRect));
+
+ float scale = lerp(START_SCALE, END_SCALE, progress);
+ context.mMatrix.setScale(scale, scale, context.mCurrentCropRect.exactCenterX(),
+ context.mCurrentCropRect.exactCenterY());
+
+ transaction.setWindowCrop(context.mLeash, context.mCurrentCropRect)
+ .setMatrix(context.mLeash, context.mMatrix, FLOAT_9)
+ .setCornerRadius(context.mLeash, mWindowCornerRadiusPx)
+ .show(context.mLeash)
+ ;
+ }
+ }
+
+ public void resetAllSurfaces(Transaction transaction) {
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+ resetSurface(context, transaction);
+ }
+ }
+
+ private void resetSurface(AnimationContext context, Transaction transaction) {
+ transaction
+ .setWindowCrop(context.mLeash, null)
+ .setCornerRadius(context.mLeash, 0.0F)
+ .setMatrix(context.mLeash, 1.0F, 0.0F, 0.0F, 1.0F)
+ .setPosition(context.mLeash,
+ (float) context.mTaskInfo.positionInParent.x,
+ (float) context.mTaskInfo.positionInParent.y);
+ }
+
+ private class AnimationContext {
+ final SurfaceControl mLeash;
+ final Rect mStartCropRect = new Rect();
+ final Rect mEndCropRect = new Rect();
+ final Rect mCurrentCropRect = new Rect();
+ final Matrix mMatrix = new Matrix();
+
+ TaskInfo mTaskInfo;
+
+ private AnimationContext(SurfaceControl leash, InsetsSource taskBarInsetsSource,
+ TaskInfo taskInfo) {
+ mLeash = leash;
+ update(taskBarInsetsSource, taskInfo);
+ }
+
+ private void update(InsetsSource taskBarInsetsSource, TaskInfo taskInfo) {
+ mTaskInfo = taskInfo;
+ mStartCropRect.set(mTaskInfo.getConfiguration().windowConfiguration.getBounds());
+
+ if (taskBarInsetsSource != null) {
+ // Only insets the cropping window with task bar when it's expanded
+ if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
+ mStartCropRect.inset(taskBarInsetsSource
+ .calculateVisibleInsets(mStartCropRect));
+ }
+ }
+
+ mEndCropRect.set(mStartCropRect);
+
+ int horizontalMargin = (int) (mEndCropRect.width() * HORIZONTAL_START_MARGIN);
+ mStartCropRect.left = mEndCropRect.left + horizontalMargin;
+ mStartCropRect.right = mEndCropRect.right - horizontalMargin;
+ int verticalMargin = (int) (mEndCropRect.height() * VERTICAL_START_MARGIN);
+ mStartCropRect.top = mEndCropRect.top + verticalMargin;
+ mStartCropRect.bottom = mEndCropRect.bottom - verticalMargin;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index cb478c84c2b7..5dacdbf4b638 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -43,6 +43,80 @@ fun FlickerTestParameter.appPairsDividerBecomesVisible() {
}
}
+fun FlickerTestParameter.splitScreenDividerBecomesVisible() {
+ layerBecomesVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+}
+
+fun FlickerTestParameter.layerBecomesVisible(
+ component: FlickerComponentName
+) {
+ assertLayers {
+ this.isInvisible(component)
+ .then()
+ .isVisible(component)
+ }
+}
+
+fun FlickerTestParameter.layerIsVisibleAtEnd(
+ component: FlickerComponentName
+) {
+ assertLayersEnd {
+ this.isVisible(component)
+ }
+}
+
+fun FlickerTestParameter.splitAppLayerBoundsBecomesVisible(
+ rotation: Int,
+ component: FlickerComponentName,
+ splitLeftTop: Boolean
+) {
+ assertLayers {
+ this.isInvisible(component)
+ .then()
+ .invoke("splitAppLayerBoundsBecomesVisible") {
+ val dividerRegion = it.layer(SPLIT_SCREEN_DIVIDER_COMPONENT).visibleRegion.region
+ it.visibleRegion(component).overlaps(if (splitLeftTop) {
+ getSplitLeftTopRegion(dividerRegion, rotation)
+ } else {
+ getSplitRightBottomRegion(dividerRegion, rotation)
+ })
+ }
+ }
+}
+
+fun FlickerTestParameter.splitAppLayerBoundsIsVisibleAtEnd(
+ rotation: Int,
+ component: FlickerComponentName,
+ splitLeftTop: Boolean
+) {
+ assertLayersEnd {
+ val dividerRegion = layer(SPLIT_SCREEN_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(component).overlaps(if (splitLeftTop) {
+ getSplitLeftTopRegion(dividerRegion, rotation)
+ } else {
+ getSplitRightBottomRegion(dividerRegion, rotation)
+ })
+ }
+}
+
+fun FlickerTestParameter.appWindowBecomesVisible(
+ component: FlickerComponentName
+) {
+ assertWm {
+ this.isAppWindowInvisible(component)
+ .then()
+ .isAppWindowVisible(component)
+ }
+}
+
+fun FlickerTestParameter.appWindowIsVisibleAtEnd(
+ component: FlickerComponentName
+) {
+ assertWmEnd {
+ this.isAppWindowVisible(component)
+ }
+}
+
fun FlickerTestParameter.dockedStackDividerIsVisibleAtEnd() {
assertLayersEnd {
this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
@@ -135,4 +209,24 @@ fun getSecondaryRegion(dividerRegion: Region, rotation: Int): Region {
Region.from(dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset, 0,
displayBounds.bounds.right, displayBounds.bounds.bottom)
}
-} \ No newline at end of file
+}
+
+fun getSplitLeftTopRegion(dividerRegion: Region, rotation: Int): Region {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ return if (displayBounds.width > displayBounds.height) {
+ Region.from(0, 0, dividerRegion.bounds.left, displayBounds.bounds.bottom)
+ } else {
+ Region.from(0, 0, displayBounds.bounds.right, dividerRegion.bounds.top)
+ }
+}
+
+fun getSplitRightBottomRegion(dividerRegion: Region, rotation: Int): Region {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ return if (displayBounds.width > displayBounds.height) {
+ Region.from(dividerRegion.bounds.right, 0, displayBounds.bounds.right,
+ displayBounds.bounds.bottom)
+ } else {
+ Region.from(0, dividerRegion.bounds.bottom, displayBounds.bounds.right,
+ displayBounds.bounds.bottom)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 40891f36a5da..f56eb6e783aa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -21,4 +21,5 @@ import com.android.server.wm.traces.common.FlickerComponentName
const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
val APP_PAIR_SPLIT_DIVIDER_COMPONENT = FlickerComponentName("", "AppPairSplitDivider#")
-val DOCKED_STACK_DIVIDER_COMPONENT = FlickerComponentName("", "DockedStackDivider#") \ No newline at end of file
+val DOCKED_STACK_DIVIDER_COMPONENT = FlickerComponentName("", "DockedStackDivider#")
+val SPLIT_SCREEN_DIVIDER_COMPONENT = FlickerComponentName("", "StageCoordinatorSplitDivider#")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
deleted file mode 100644
index c9cab39b7d8b..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ /dev/null
@@ -1,115 +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.apppairs
-
-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.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher. When the device doesn't support non-resizable in multi window
- * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs should not pair
- * non-resizable apps.
- *
- * To run this test: `atest WMShellFlickerTests:AppPairsTestCannotPairNonResizeableApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestCannotPairNonResizeableApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- nonResizeableApp?.launchViaIntent(wmHelper)
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
- }
- }
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
-
- @Ignore
- @Test
- fun onlyResizeableAppWindowVisible() {
- val nonResizeableApp = nonResizeableApp
- require(nonResizeableApp != null) {
- "Non resizeable app not initialized"
- }
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- isAppWindowInvisible(primaryApp.component)
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
deleted file mode 100644
index 60c32c99d1ff..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ /dev/null
@@ -1,104 +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.apppairs
-
-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.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher.
- * To run this test: `atest WMShellFlickerTests:AppPairsTestPairPrimaryAndSecondaryApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestPairPrimaryAndSecondaryApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersEnd {
- val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
- visibleRegion(primaryApp.component)
- .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.component)
- .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
deleted file mode 100644
index 24869a802167..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ /dev/null
@@ -1,128 +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.apppairs
-
-import android.view.Display
-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.dsl.FlickerBuilder
-import com.android.server.wm.traces.common.WindowManagerConditionsFactory
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher. When the device supports non-resizable in multi window
- * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs can pair
- * non-resizable apps.
- *
- * To run this test: `atest WMShellFlickerTests:AppPairsTestSupportPairNonResizeableApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestSupportPairNonResizeableApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- nonResizeableApp?.launchViaIntent(wmHelper)
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- val waitConditions = mutableListOf(
- WindowManagerConditionsFactory.isWindowVisible(primaryApp.component),
- WindowManagerConditionsFactory.isLayerVisible(primaryApp.component),
- WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY))
-
- nonResizeableApp?.let {
- waitConditions.add(
- WindowManagerConditionsFactory.isWindowVisible(nonResizeableApp.component))
- waitConditions.add(
- WindowManagerConditionsFactory.isLayerVisible(nonResizeableApp.component))
- }
- wmHelper.waitFor(*waitConditions.toTypedArray())
- }
- }
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowVisible() {
- val nonResizeableApp = nonResizeableApp
- require(nonResizeableApp != null) {
- "Non resizeable app not initialized"
- }
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- isAppWindowVisible(primaryApp.component)
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
deleted file mode 100644
index 007415d19860..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ /dev/null
@@ -1,121 +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.apppairs
-
-import android.os.SystemClock
-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.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launch app from launcher.
- * To run this test: `atest WMShellFlickerTests:AppPairsTestUnpairPrimaryAndSecondaryApps`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class AppPairsTestUnpairPrimaryAndSecondaryApps(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = false))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
-
- @Ignore
- @Test
- fun bothAppWindowsInvisible() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(primaryApp.component)
- isAppWindowInvisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appsStartingBounds() {
- testSpec.assertLayersStart {
- val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
- visibleRegion(primaryApp.component)
- .coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.component)
- .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- }
-
- @Ignore
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersEnd {
- notContains(primaryApp.component)
- notContains(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = AppPairsHelper.TEST_REPETITIONS)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
deleted file mode 100644
index 3e17948b4a84..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ /dev/null
@@ -1,178 +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.apppairs
-
-import android.app.Instrumentation
-import android.content.Context
-import android.system.helpers.ActivityHelper
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-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.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.parser.toFlickerComponent
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
-import com.android.wm.shell.flicker.helpers.BaseAppHelper
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import com.android.wm.shell.flicker.testapp.Components
-import org.junit.After
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-
-abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val context: Context = instrumentation.context
- protected val activityHelper = ActivityHelper.getInstance()
- protected val appPairsHelper = AppPairsHelper(instrumentation,
- Components.SplitScreenActivity.LABEL,
- Components.SplitScreenActivity.COMPONENT.toFlickerComponent())
-
- protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation)
- protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- protected open val nonResizeableApp: SplitScreenHelper? =
- SplitScreenHelper.getNonResizeable(instrumentation)
- protected var primaryTaskId = ""
- protected var secondaryTaskId = ""
- protected var nonResizeableTaskId = ""
- private var prevDevEnableNonResizableMultiWindow = 0
-
- @Before
- open fun setup() {
- prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
- if (prevDevEnableNonResizableMultiWindow != 0) {
- // Turn off the development option
- setDevEnableNonResizableMultiWindow(context, 0)
- }
- }
-
- @After
- open fun teardown() {
- setDevEnableNonResizableMultiWindow(context, prevDevEnableNonResizableMultiWindow)
- }
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- transition(this)
- }
- }
-
- internal open val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(testSpec.startRotation)
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- nonResizeableApp?.launchViaIntent(wmHelper)
- updateTasksId()
- }
- }
- teardown {
- eachRun {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, pair = false))
- executeShellCommand(composePairsCommand(
- primaryTaskId, nonResizeableTaskId, pair = false))
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- nonResizeableApp?.exit(wmHelper)
- }
- }
- }
-
- protected fun updateTasksId() {
- primaryTaskId = getTaskIdForActivity(
- primaryApp.component.packageName, primaryApp.component.className).toString()
- secondaryTaskId = getTaskIdForActivity(
- secondaryApp.component.packageName, secondaryApp.component.className).toString()
- val nonResizeableApp = nonResizeableApp
- if (nonResizeableApp != null) {
- nonResizeableTaskId = getTaskIdForActivity(
- nonResizeableApp.component.packageName,
- nonResizeableApp.component.className).toString()
- }
- }
-
- private fun getTaskIdForActivity(pkgName: String, activityName: String): Int {
- return activityHelper.getTaskIdForActivity(pkgName, activityName)
- }
-
- internal fun executeShellCommand(cmd: String) {
- BaseAppHelper.executeShellCommand(instrumentation, cmd)
- }
-
- internal fun composePairsCommand(
- primaryApp: String,
- secondaryApp: String,
- pair: Boolean
- ): String = buildString {
- // dumpsys activity service SystemUIService WMShell {pair|unpair} ${TASK_ID_1} ${TASK_ID_2}
- append("dumpsys activity service SystemUIService WMShell ")
- if (pair) {
- append("pair ")
- } else {
- append("unpair ")
- }
- append("$primaryApp $secondaryApp")
- }
-
- @Ignore
- @Test
- open fun navBarLayerIsVisible() {
- testSpec.navBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- open fun statusBarLayerIsVisible() {
- testSpec.statusBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- open fun navBarWindowIsVisible() {
- testSpec.navBarWindowIsVisible()
- }
-
- @Ignore
- @Test
- open fun statusBarWindowIsVisible() {
- testSpec.statusBarWindowIsVisible()
- }
-
- @Ignore
- @Test
- open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @Ignore
- @Test
- open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
deleted file mode 100644
index 8446b37dbf06..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# window manager > wm shell > Split Screen
-# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
deleted file mode 100644
index b0c3ba20d948..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ /dev/null
@@ -1,109 +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.apppairs
-
-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.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open apps to app pairs and rotate.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsInAppPairsMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class RotateTwoLaunchedAppsInAppPairsMode(
- testSpec: FlickerTestParameter
-) : RotateTwoLaunchedAppsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, true /* pair */))
- waitAppsShown(primaryApp, secondaryApp)
- setRotation(testSpec.endRotation)
- }
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- fun appPairsPrimaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- primaryApp.component)
-
- @Ignore
- @Test
- fun appPairsSecondaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- secondaryApp.component)
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
- )
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
deleted file mode 100644
index ae56c7732a4d..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ /dev/null
@@ -1,117 +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.apppairs
-
-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.Group1
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open apps to app pairs and rotate.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsRotateAndEnterAppPairsMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
- testSpec: FlickerTestParameter
-) : RotateTwoLaunchedAppsTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.endRotation)
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- waitAppsShown(primaryApp, secondaryApp)
- }
- }
-
- @Ignore
- @Test
- fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
-
- @Ignore
- @Test
- override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
-
- @Ignore
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @Ignore
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(primaryApp.component)
- isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Ignore
- @Test
- fun appPairsPrimaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- primaryApp.component)
-
- @Ignore
- @Test
- fun appPairsSecondaryBoundsIsVisibleAtEnd() =
- testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
- secondaryApp.component)
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
deleted file mode 100644
index b1f1c9e539df..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ /dev/null
@@ -1,76 +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.apppairs
-
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.Assume.assumeFalse
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-
-abstract class RotateTwoLaunchedAppsTransition(
- testSpec: FlickerTestParameter
-) : AppPairsTransition(testSpec) {
- override val nonResizeableApp: SplitScreenHelper?
- get() = null
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(Surface.ROTATION_0)
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- updateTasksId()
- }
- }
- teardown {
- eachRun {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, pair = false))
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- }
- }
- }
-
- @Before
- override fun setup() {
- // AppPairs hasn't been updated to Shell Transition. There will be conflict on rotation.
- assumeFalse(isShellTransitionsEnabled())
- super.setup()
- }
-
- @Ignore
- @Test
- override fun navBarLayerIsVisible() {
- super.navBarLayerIsVisible()
- }
-
- @Ignore
- @Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
index 0ec9b2d869a8..b902e5d1b454 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.content.res.Resources
import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.wm.shell.flicker.testapp.Components
@@ -32,11 +31,6 @@ class SplitScreenHelper(
const val TEST_REPETITIONS = 1
const val TIMEOUT_MS = 3_000L
- // TODO: remove all legacy split screen flicker tests when legacy split screen is fully
- // deprecated.
- fun isUsingLegacySplit(): Boolean =
- Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useLegacySplit)
-
fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper =
SplitScreenHelper(instrumentation,
Components.SplitScreenActivity.LABEL,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
deleted file mode 100644
index c86a1229d8d8..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ /dev/null
@@ -1,116 +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.legacysplitscreen
-
-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.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open activity and dock to primary split screen
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenDockActivity`
- */
-@Presubmit
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class EnterSplitScreenDockActivity(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT,
- splitScreenApp.component, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT, LAUNCHER_COMPONENT)
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0), // bugId = 179116910
- supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
deleted file mode 100644
index 2f9244be9c18..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
+++ /dev/null
@@ -1,104 +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.legacysplitscreen
-
-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.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from a detached recent task
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenFromDetachedRecentTask`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-class EnterSplitScreenFromDetachedRecentTask(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- // Press back to remove the task, but it should still be shown in recent.
- device.pressBack()
- }
- }
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
deleted file mode 100644
index 1740c3ec24ca..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ /dev/null
@@ -1,126 +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.legacysplitscreen
-
-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.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open activity to primary split screen and dock secondary activity to side
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenLaunchToSide`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class EnterSplitScreenLaunchToSide(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
- secondaryApp.component, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
-
- @Presubmit
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(secondaryApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
deleted file mode 100644
index 4c063b918e96..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ /dev/null
@@ -1,110 +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.legacysplitscreen
-
-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.Group4
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.canSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Assert
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from non-resizable activity. When the device doesn't support
- * non-resizable in multi window, there should be no button to enter split screen for non-resizable
- * activity.
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-class EnterSplitScreenNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- if (device.canSplitScreen(wmHelper)) {
- Assert.fail("Non-resizeable app should not enter split screen")
- }
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- nonResizeableApp.component,
- splitScreenApp.component)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
deleted file mode 100644
index f75dee619564..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
+++ /dev/null
@@ -1,115 +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.legacysplitscreen
-
-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.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test enter split screen from non-resizable activity. When the device supports
- * non-resizable in multi window, there should be a button to enter split screen for non-resizable
- * activity.
- *
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group2
-class EnterSplitScreenSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT,
- nonResizeableApp.component,
- splitScreenApp.component)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
deleted file mode 100644
index ef7d65e8a732..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ /dev/null
@@ -1,124 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open resizeable activity split in primary, and drag divider to bottom exit split screen
- * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottom`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class ExitLegacySplitScreenFromBottom(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- teardown {
- eachRun {
- splitScreenApp.exit(wmHelper)
- }
- }
- transitions {
- device.exitSplitScreenFromBottom(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- splitScreenApp.component, secondaryApp.component,
- FlickerComponentName.SNAPSHOT)
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
- .then()
- .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
- }
- }
-
- @FlakyTest
- @Test
- fun appWindowBecomesInVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(secondaryApp.component)
- .then()
- .isAppWindowInvisible(secondaryApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // b/175687842
- )
- }
- }
-} \ No newline at end of file
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
deleted file mode 100644
index d913a6d85d3d..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ /dev/null
@@ -1,129 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test dock activity to primary split screen, and open secondary to side, exit primary split
- * and test secondary activity become full screen.
- * To run this test: `atest WMShellFlickerTests:ExitPrimarySplitScreenShowSecondaryFullscreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class ExitPrimarySplitScreenShowSecondaryFullscreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- teardown {
- eachRun {
- secondaryApp.exit(wmHelper)
- }
- }
- transitions {
- splitScreenApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- // TODO(b/175687842) Can not find Split screen divider, use exit() instead
- splitScreenApp.exit(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- splitScreenApp.component, secondaryApp.component,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun appWindowBecomesInVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
deleted file mode 100644
index f3ff7b156aaf..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
+++ /dev/null
@@ -1,196 +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.legacysplitscreen
-
-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.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via intent in split screen mode. When the device does not
- * support non-resizable in multi window, it should trigger exit split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromIntentNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- nonResizeableApp.component, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun resizableAppLayerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.notContains(nonResizeableApp.component)
- .then()
- .isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Assets that [splitScreenApp] exists at the start of the trace and, once it becomes
- * invisible, it remains invisible until the end of the trace.
- */
- @Presubmit
- @Test
- fun resizableAppWindowBecomesInvisible() {
- testSpec.assertWm {
- // when the activity gets PAUSED the window may still be marked as visible
- // it will be updated in the next log entry. This occurs because we record 1x
- // per frame, thus ignore activity check here
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- /**
- * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
- * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
- * visible, it remains visible until the end of the trace.
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.notContains(nonResizeableApp.component)
- .then()
- // we log once per frame, upon logging, window may be visible or not depending
- // on what was processed until that moment. Both behaviors are correct
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Asserts that both the app window and the activity are visible at the end of the trace
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- fun onlyNonResizableAppWindowIsVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
deleted file mode 100644
index 42e707ab0850..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
+++ /dev/null
@@ -1,153 +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.legacysplitscreen
-
-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.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via intent in split screen mode. When the device supports
- * non-resizable in multi window, it should show the non-resizable app in split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromIntentSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- nonResizeableApp.component, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- /**
- * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
- * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
- * visible, it remains visible until the end of the trace.
- */
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.notContains(nonResizeableApp.component)
- .then()
- // we log once per frame, upon logging, window may be visible or not depending
- // on what was processed until that moment. Both behaviors are correct
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun bothAppsWindowsAreVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
deleted file mode 100644
index c1fba7d1530c..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
+++ /dev/null
@@ -1,169 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via recent overview in split screen mode. When the device does
- * not support non-resizable in multi window, it should trigger exit split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromRecentNotSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, -1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun resizableAppLayerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(splitScreenApp.component)
- .then()
- .isInvisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun resizableAppWindowBecomesInvisible() {
- testSpec.assertWm {
- // when the activity gets PAUSED the window may still be marked as visible
- // it will be updated in the next log entry. This occurs because we record 1x
- // per frame, thus ignore activity check here
- this.isAppWindowVisible(splitScreenApp.component)
- .then()
- // immediately after the window (after onResume and before perform relayout)
- // the activity is invisible. This may or not be logged, since we record 1x
- // per frame, thus ignore activity check here
- .isAppWindowInvisible(splitScreenApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(nonResizeableApp.component)
- .then()
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
-
- @Presubmit
- @Test
- fun onlyNonResizableAppWindowIsVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowInvisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
deleted file mode 100644
index 6ac8683ac054..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
+++ /dev/null
@@ -1,155 +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.legacysplitscreen
-
-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.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test launch non-resizable activity via recent overview in split screen mode. When the device
- * supports non-resizable in multi window, it should show the non-resizable app in split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenFromRecentSupportNonResizable(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- cleanSetup(this)
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
- TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Before
- override fun setup() {
- super.setup()
- setSupportsNonResizableMultiWindow(instrumentation, 1)
- }
-
- @After
- override fun teardown() {
- super.teardown()
- resetMultiWindowConfig(instrumentation)
- }
-
- @Presubmit
- @Test
- fun nonResizableAppLayerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(nonResizeableApp.component)
- .then()
- .isVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun nonResizableAppWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(nonResizeableApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(nonResizeableApp.component, isOptional = true)
- .then()
- // if the window reappears after re-parenting it will most likely not
- // be visible in the first log entry (because we log only 1x per frame)
- .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun bothAppsWindowsAreVisibleAtEnd() {
- testSpec.assertWmEnd {
- isAppWindowVisible(splitScreenApp.component)
- isAppWindowVisible(nonResizeableApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
deleted file mode 100644
index b01f41c9e2ec..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
+++ /dev/null
@@ -1,47 +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.legacysplitscreen
-
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-
-abstract class LegacySplitScreenRotateTransition(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- }
- }
- teardown {
- eachRun {
- splitScreenApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-}
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
deleted file mode 100644
index fb1004bda0cb..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ /dev/null
@@ -1,160 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-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.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
-import com.android.wm.shell.flicker.helpers.SimpleAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncher`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class LegacySplitScreenToLauncher(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- private val testApp = SimpleAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.endRotation)
- device.launchSplitScreen(wmHelper)
- device.waitForIdle()
- }
- }
- teardown {
- eachRun {
- testApp.exit(wmHelper)
- }
- }
- transitions {
- device.exitSplitScreen()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
-
- @Presubmit
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @FlakyTest
- @Test
- fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible()
-
- @FlakyTest
- @Test
- fun layerBecomesInvisible() {
- testSpec.assertLayers {
- this.isVisible(testApp.component)
- .then()
- .isInvisible(testApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun focusDoesNotChange() {
- testSpec.assertEventLog {
- this.focusDoesNotChange()
- }
- }
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- // b/161435597 causes the test not to work on 90 degrees
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
deleted file mode 100644
index a4a1f617e497..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ /dev/null
@@ -1,149 +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/LICENSE2.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.legacysplitscreen
-
-import android.app.Instrumentation
-import android.content.Context
-import android.support.test.launcherhelper.LauncherStrategyFactory
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.After
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Test
-
-abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) {
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val context: Context = instrumentation.context
- protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
- protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation)
- protected val LAUNCHER_COMPONENT = FlickerComponentName("",
- LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage)
- private var prevDevEnableNonResizableMultiWindow = 0
-
- @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())
- prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
- if (prevDevEnableNonResizableMultiWindow != 0) {
- // Turn off the development option
- setDevEnableNonResizableMultiWindow(context, 0)
- }
- }
-
- @After
- open fun teardown() {
- setDevEnableNonResizableMultiWindow(context, prevDevEnableNonResizableMultiWindow)
- }
-
- /**
- * List of windows that are ignored when verifying that visible elements appear on 2
- * consecutive entries in the trace.
- *
- * b/182720234
- */
- open val ignoredWindows: List<FlickerComponentName> = listOf(
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- protected open val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- teardown {
- eachRun {
- secondaryApp.exit(wmHelper)
- splitScreenApp.exit(wmHelper)
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- transition(this)
- }
- }
-
- internal open val cleanSetup: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- teardown {
- eachRun {
- nonResizeableApp.exit(wmHelper)
- splitScreenApp.exit(wmHelper)
- device.pressHome()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
-
- @FlakyTest(bugId = 178447631)
- @Test
- open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoredWindows)
- }
- }
-
- @FlakyTest(bugId = 178447631)
- @Test
- open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoredWindows)
- }
- }
-
- companion object {
- internal val LIVE_WALLPAPER_COMPONENT = FlickerComponentName("",
- "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2")
- internal val LETTERBOX_COMPONENT = FlickerComponentName("", "Letterbox")
- internal val TOAST_COMPONENT = FlickerComponentName("", "Toast")
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
deleted file mode 100644
index 8446b37dbf06..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# window manager > wm shell > Split Screen
-# Bug component: 928697
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
deleted file mode 100644
index 087b21c544c5..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ /dev/null
@@ -1,122 +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.legacysplitscreen
-
-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.annotation.Group2
-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.statusBarLayerIsVisible
-import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class OpenAppToLegacySplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- }
-
- override val ignoredWindows: List<FlickerComponentName>
- get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
- FlickerComponentName.SPLASH_SCREEN,
- FlickerComponentName.SNAPSHOT)
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Presubmit
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @Presubmit
- @Test
- fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible()
-
- @FlakyTest
- @Test
- fun layerBecomesVisible() {
- testSpec.assertLayers {
- this.isInvisible(splitScreenApp.component)
- .then()
- .isVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun focusChanges() {
- testSpec.assertEventLog {
- this.focusChanges(splitScreenApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity")
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
- )
- }
- }
-}
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
deleted file mode 100644
index e2da1a4565c0..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ /dev/null
@@ -1,228 +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.legacysplitscreen
-
-import android.util.Rational
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import androidx.test.uiautomator.By
-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.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.resizeSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-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.statusBarLayerIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.server.wm.traces.common.region.Region
-import com.android.server.wm.traces.parser.toFlickerComponent
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
-import com.android.wm.shell.flicker.helpers.SimpleAppHelper
-import com.android.wm.shell.flicker.testapp.Components
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test split screen resizing window transitions.
- * To run this test: `atest WMShellFlickerTests:ResizeLegacySplitScreen`
- *
- * Currently it runs only in 0 degrees because of b/156100803
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 159096424)
-@Group2
-class ResizeLegacySplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenTransition(testSpec) {
- private val testAppTop = SimpleAppHelper(instrumentation)
- private val testAppBottom = ImeAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(testSpec.startRotation)
- this.launcherStrategy.clearRecentAppsFromOverview()
- testAppBottom.launchViaIntent(wmHelper)
- device.pressHome()
- testAppTop.launchViaIntent(wmHelper)
- device.waitForIdle()
- device.launchSplitScreen(wmHelper)
- val snapshot =
- device.findObject(By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- testAppBottom.openIME(device)
- device.pressBack()
- device.resizeSplitScreen(startRatio)
- }
- }
- teardown {
- eachRun {
- testAppTop.exit(wmHelper)
- testAppBottom.exit(wmHelper)
- }
- }
- transitions {
- device.resizeSplitScreen(stopRatio)
- }
- }
-
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest(bugId = 156223549)
- @Test
- fun topAppWindowIsAlwaysVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @FlakyTest(bugId = 156223549)
- @Test
- fun bottomAppWindowIsAlwaysVisible() {
- testSpec.assertWm {
- this.isAppWindowVisible(Components.ImeActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
-
- @Test
- fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
-
- @Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
-
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Test
- fun topAppLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun bottomAppLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(Components.ImeActivity.COMPONENT.toFlickerComponent())
- }
- }
-
- @Test
- fun dividerLayerIsAlwaysVisible() {
- testSpec.assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
- }
- }
-
- @FlakyTest
- @Test
- fun appsStartingBounds() {
- testSpec.assertLayersStart {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
-
- val topAppBounds = Region.from(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region.from(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
- visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- .coversExactly(topAppBounds)
- visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
- .coversExactly(bottomAppBounds)
- }
- }
-
- @FlakyTest
- @Test
- fun appsEndingBounds() {
- testSpec.assertLayersStart {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
-
- val topAppBounds = Region.from(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region.from(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
-
- visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
- .coversExactly(topAppBounds)
- visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
- .coversExactly(bottomAppBounds)
- }
- }
-
- @Test
- fun focusDoesNotChange() {
- testSpec.assertEventLog {
- focusDoesNotChange()
- }
- }
-
- companion object {
- private val startRatio = Rational(1, 3)
- private val stopRatio = Rational(2, 3)
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
- .map {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- val newName = "${FlickerTestParameter.defaultName(it)}_$description"
- FlickerTestParameter(it.config, nameOverride = newName)
- }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
deleted file mode 100644
index d703ea082c87..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ /dev/null
@@ -1,114 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test dock activity to primary split screen and rotate
- * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppAndEnterSplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateOneLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- device.launchSplitScreen(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
deleted file mode 100644
index 6b1883914e59..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Rotate
- * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppInSplitScreenMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateOneLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.startRotation)
- device.launchSplitScreen(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() = testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(
- testSpec.startRotation, splitScreenApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(splitScreenApp.component)
- .then()
- .isAppWindowVisible(splitScreenApp.component)
- }
- }
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
deleted file mode 100644
index acd658b5ba56..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ /dev/null
@@ -1,136 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppAndEnterSplitScreen`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateTwoLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- transitions {
- this.setRotation(testSpec.startRotation)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @Presubmit
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- // when the app is launched, first the activity becomes visible, then the
- // SnapshotStartingWindow appears and then the app window becomes visible.
- // Because we log WM once per frame, sometimes the activity and the window
- // become visible in the same entry, sometimes not, thus it is not possible to
- // assert the visibility of the activity here
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- // during re-parenting, the window may disappear and reappear from the
- // trace, this occurs because we log only 1x per frame
- .notContains(secondaryApp.component, isOptional = true)
- .then()
- // if the window reappears after re-parenting it will most likely not
- // be visible in the first log entry (because we log only 1x per frame)
- .isAppWindowInvisible(secondaryApp.component, isOptional = true)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
deleted file mode 100644
index b40be8b5f401..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ /dev/null
@@ -1,133 +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.legacysplitscreen
-
-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.annotation.Group2
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppInSplitScreenMode`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
-class RotateTwoLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestParameter
-) : LegacySplitScreenRotateTransition(testSpec) {
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- eachRun {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- this.setRotation(testSpec.startRotation)
- }
- }
- transitions {
- this.setRotation(testSpec.startRotation)
- }
- }
-
- @Presubmit
- @Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
-
- @Presubmit
- @Test
- fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- splitScreenApp.component)
-
- @Presubmit
- @Test
- fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
- testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation,
- secondaryApp.component)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
-
- @FlakyTest(bugId = 206753786)
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
-
- @FlakyTest
- @Test
- fun appWindowBecomesVisible() {
- testSpec.assertWm {
- this.isAppWindowInvisible(secondaryApp.component)
- .then()
- .isAppWindowVisible(secondaryApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
-
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
- }
- }
-}
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
index 37e9344348d9..c6a705dacb8d 100644
--- 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
@@ -80,7 +80,17 @@ class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransit
/** {@inheritDoc} */
@FlakyTest(bugId = 206753786)
@Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ override fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales_ShellTransit() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
/** {@inheritDoc} */
@FlakyTest(bugId = 197726610)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
index 1a21d32f568c..fe51228230cb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.flicker.pip
-import androidx.test.filters.FlakyTest
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -35,7 +35,6 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-@FlakyTest(bugId = 217777115)
class PipKeyboardTestShellTransit(testSpec: FlickerTestParameter) : PipKeyboardTest(testSpec) {
@Before
@@ -43,7 +42,7 @@ class PipKeyboardTestShellTransit(testSpec: FlickerTestParameter) : PipKeyboardT
Assume.assumeTrue(isShellTransitionsEnabled)
}
- @FlakyTest(bugId = 214452854)
+ @Presubmit
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
} \ 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
deleted file mode 100644
index 21175a0767a5..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ /dev/null
@@ -1,148 +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.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.annotation.Group4
-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.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
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip with split-screen.
- * To run this test: `atest WMShellFlickerTests:PipLegacySplitScreenTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
- private val imeApp = ImeAppHelper(instrumentation)
- private val testApp = FixedAppHelper(instrumentation)
-
- @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())
- }
-
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- test {
- removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
- pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"),
- wmHelper = wmHelper)
- }
- }
- transitions {
- testApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- imeApp.launchViaIntent(wmHelper)
- }
- teardown {
- eachRun {
- imeApp.exit(wmHelper)
- testApp.exit(wmHelper)
- }
- test {
- removeAllTasksButHome()
- }
- }
- }
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
- @FlakyTest(bugId = 161435597)
- @Test
- fun pipWindowInsideDisplayBounds() {
- testSpec.assertWmVisibleRegion(pipApp.component) {
- coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun bothAppWindowsVisible() {
- testSpec.assertWmEnd {
- isAppWindowVisible(testApp.component)
- isAppWindowVisible(imeApp.component)
- doNotOverlap(testApp.component, imeApp.component)
- }
- }
-
- @FlakyTest(bugId = 161435597)
- @Test
- fun pipLayerInsideDisplayBounds() {
- testSpec.assertLayersVisibleRegion(pipApp.component) {
- coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun bothAppLayersVisible() {
- testSpec.assertLayersEnd {
- visibleRegion(testApp.component).coversAtMost(displayBounds)
- visibleRegion(imeApp.component).coversAtMost(displayBounds)
- }
- }
-
- @FlakyTest(bugId = 161435597)
- @Test
- override fun entireScreenCovered() = super.entireScreenCovered()
-
- companion object {
- const val TEST_REPETITIONS = 2
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = TEST_REPETITIONS
- )
- }
- }
-}
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 c1ee1a7cbb35..4618fb376f7f 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
@@ -27,12 +27,10 @@ import com.android.server.wm.flicker.annotation.Group4
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.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -141,14 +139,6 @@ open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testS
@Presubmit
@Test
fun pipLayerRotates_StartingBounds() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- pipLayerRotates_StartingBounds_internal()
- }
-
- @FlakyTest(bugId = 228024285)
- @Test
- fun pipLayerRotates_StartingBounds_ShellTransit() {
- Assume.assumeTrue(isShellTransitionsEnabled)
pipLayerRotates_StartingBounds_internal()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
new file mode 100644
index 000000000000..702710caded7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 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.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
+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.dsl.FlickerBuilder
+import com.android.wm.shell.flicker.appWindowBecomesVisible
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import com.android.wm.shell.flicker.layerBecomesVisible
+import com.android.wm.shell.flicker.layerIsVisibleAtEnd
+import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
+import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test enter split screen by dragging app icon from all apps.
+ * This test is only for large screen devices.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromAllApps`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class EnterSplitScreenByDragFromAllApps(
+ testSpec: FlickerTestParameter
+) : SplitScreenBase(testSpec) {
+
+ @Before
+ open fun before() {
+ Assume.assumeTrue(taplInstrumentation.isTablet)
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
+ setup {
+ eachRun {
+ taplInstrumentation.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ taplInstrumentation.launchedAppState.taskbar
+ .openAllApps()
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.component.packageName,
+ primaryApp.component.packageName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun dividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp.component)
+
+ @Presubmit
+ @Test
+ fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp.component)
+
+ @Presubmit
+ @Test
+ fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+ testSpec.endRotation, primaryApp.component, false /* splitLeftTop */)
+
+ @Presubmit
+ @Test
+ fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
+ testSpec.endRotation, secondaryApp.component, true /* splitLeftTop */)
+
+ @Presubmit
+ @Test
+ fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp.component)
+
+ @Presubmit
+ @Test
+ fun secondaryAppWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(secondaryApp.component)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ repetitions = SplitScreenHelper.TEST_REPETITIONS,
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes =
+ listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
new file mode 100644
index 000000000000..52c2daf96a3c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.splitscreen
+
+import android.app.Instrumentation
+import android.content.Context
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+
+abstract class SplitScreenBase(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val taplInstrumentation = LauncherInstrumentation()
+ protected val context: Context = instrumentation.context
+ protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation)
+ protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(this)
+ }
+ }
+
+ protected open val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ test {
+ taplInstrumentation.setEnableRotation(true)
+ setRotation(testSpec.startRotation)
+ taplInstrumentation.setExpectedRotation(testSpec.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
deleted file mode 100644
index e73d9aaf190a..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ /dev/null
@@ -1,123 +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.apppairs;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.hardware.display.DisplayManager;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link AppPair}
- * Build/Install/Run:
- * atest WMShellUnitTests:AppPairTests
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairTests extends ShellTestCase {
-
- private AppPairsController mController;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- spyOn(mController);
- }
-
- @After
- public void tearDown() {}
-
- @Test
- @UiThreadTest
- public void testContains() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- pair.unpair();
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- }
-
- @Test
- @UiThreadTest
- public void testVanishUnpairs() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- pair.onTaskVanished(task1);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- }
-
- @Test
- @UiThreadTest
- public void testOnTaskInfoChanged_notSupportsMultiWindow() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- task1.supportsMultiWindow = false;
- pair.onTaskInfoChanged(task1);
- verify(mController).unpair(pair.getRootTaskId());
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
deleted file mode 100644
index 505c153eff9c..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ /dev/null
@@ -1,104 +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.apppairs;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.hardware.display.DisplayManager;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairsController} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairsControllerTests extends ShellTestCase {
- private TestAppPairsController mController;
- private TestAppPairsPool mPool;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- mPool = mController.getPool();
- }
-
- @After
- public void tearDown() {}
-
- @Test
- @UiThreadTest
- public void testPairUnpair() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
- assertThat(mPool.poolSize()).isGreaterThan(0);
-
- mController.unpair(task2.taskId);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- assertThat(mPool.poolSize()).isGreaterThan(1);
- }
-
- @Test
- @UiThreadTest
- public void testUnpair_DontReleaseToPool() {
- final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
- final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
-
- final AppPair pair = mController.pairInner(task1, task2);
- assertThat(pair.contains(task1.taskId)).isTrue();
- assertThat(pair.contains(task2.taskId)).isTrue();
-
- mController.unpair(task2.taskId, false /* releaseToPool */);
- assertThat(pair.contains(task1.taskId)).isFalse();
- assertThat(pair.contains(task2.taskId)).isFalse();
- assertThat(mPool.poolSize()).isEqualTo(1);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
deleted file mode 100644
index a3f134ee97ed..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ /dev/null
@@ -1,77 +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.apppairs;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairsPool} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairsPoolTests extends ShellTestCase {
- private TestAppPairsController mController;
- private TestAppPairsPool mPool;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private DisplayController mDisplayController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- mController = new TestAppPairsController(
- mTaskOrganizer,
- mSyncQueue,
- mDisplayController);
- mPool = mController.getPool();
- }
-
- @After
- public void tearDown() {}
-
- @Test
- public void testInitialState() {
- // Pool should always start off with at least 1 entry.
- assertThat(mPool.poolSize()).isGreaterThan(0);
- }
-
- @Test
- public void testAcquireRelease() {
- assertThat(mPool.poolSize()).isGreaterThan(0);
- final AppPair appPair = mPool.acquire();
- assertThat(mPool.poolSize()).isGreaterThan(0);
- mPool.release(appPair);
- assertThat(mPool.poolSize()).isGreaterThan(1);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
deleted file mode 100644
index 294bc1276291..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ /dev/null
@@ -1,42 +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.apppairs;
-
-import static org.mockito.Mockito.mock;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-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;
-
-public class TestAppPairsController extends AppPairsController {
- private TestAppPairsPool mPool;
-
- public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController) {
- super(organizer, syncQueue, displayController, mock(ShellExecutor.class),
- mock(DisplayImeController.class), mock(DisplayInsetsController.class));
- mPool = new TestAppPairsPool(this);
- setPairsPool(mPool);
- }
-
- TestAppPairsPool getPool() {
- return mPool;
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
deleted file mode 100644
index 1ee7fff44892..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
+++ /dev/null
@@ -1,36 +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.apppairs;
-
-import android.app.ActivityManager;
-
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-
-public class TestAppPairsPool extends AppPairsPool{
- TestAppPairsPool(AppPairsController controller) {
- super(controller);
- }
-
- @Override
- void incrementPool() {
- final AppPair entry = new AppPair(mController);
- final ActivityManager.RunningTaskInfo info =
- new TestRunningTaskInfoBuilder().build();
- entry.onTaskAppeared(info, null /* leash */);
- release(entry);
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index fcfcbfa091db..8192a49305bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -20,7 +20,6 @@ import static android.window.BackNavigationInfo.KEY_TRIGGER_BACK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -77,6 +76,7 @@ import org.mockito.MockitoAnnotations;
public class BackAnimationControllerTest {
private static final String ANIMATION_ENABLED = "1";
+
private final TestShellExecutor mShellExecutor = new TestShellExecutor();
@Rule
@@ -129,7 +129,7 @@ public class BackAnimationControllerTest {
new RemoteCallback((bundle) -> {}),
onBackInvokedCallback);
try {
- doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation(anyBoolean());
+ doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation();
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
@@ -137,7 +137,7 @@ public class BackAnimationControllerTest {
private void createNavigationInfo(BackNavigationInfo.Builder builder) {
try {
- doReturn(builder.build()).when(mActivityTaskManager).startBackNavigation(anyBoolean());
+ doReturn(builder.build()).when(mActivityTaskManager).startBackNavigation();
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
@@ -183,8 +183,7 @@ public class BackAnimationControllerTest {
// b/207481538, we check that the surface is not moved for now, we can re-enable this once
// we implement the animation
verify(mTransaction, never()).setScale(eq(screenshotSurface), anyInt(), anyInt());
- verify(mTransaction, never()).setPosition(
- animationTarget.leash, 100, 100);
+ verify(mTransaction, never()).setPosition(animationTarget.leash, 100, 100);
verify(mTransaction, atLeastOnce()).apply();
}
@@ -229,33 +228,6 @@ public class BackAnimationControllerTest {
}
@Test
- public void animationDisabledFromSettings() throws RemoteException {
- // Toggle the setting off
- Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
- mController = new BackAnimationController(
- mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
- mActivityTaskManager, mContext,
- mContentResolver);
- mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
-
- RemoteAnimationTarget animationTarget = createAnimationTarget();
- IOnBackInvokedCallback appCallback = mock(IOnBackInvokedCallback.class);
- ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
- createNavigationInfo(animationTarget, null, null,
- BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback);
-
- triggerBackGesture();
-
- verify(appCallback, never()).onBackStarted();
- verify(appCallback, never()).onBackProgressed(backEventCaptor.capture());
- verify(appCallback, times(1)).onBackInvoked();
-
- verify(mIOnBackInvokedCallback, never()).onBackStarted();
- verify(mIOnBackInvokedCallback, never()).onBackProgressed(backEventCaptor.capture());
- verify(mIOnBackInvokedCallback, never()).onBackInvoked();
- }
-
- @Test
public void ignoresGesture_transitionInProgress() throws RemoteException {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget();
@@ -269,13 +241,22 @@ public class BackAnimationControllerTest {
reset(mIOnBackInvokedCallback);
// Verify that we prevent animation from restarting if another gestures happens before
// the previous transition is finished.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
verifyNoMoreInteractions(mIOnBackInvokedCallback);
// Verify that we start accepting gestures again once transition finishes.
mController.onBackToLauncherAnimationFinished();
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
+ BackEvent.EDGE_LEFT);
verify(mIOnBackInvokedCallback).onBackStarted();
}
@@ -291,11 +272,44 @@ public class BackAnimationControllerTest {
// Simulate transition timeout.
mShellExecutor.flushAll();
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
+ BackEvent.EDGE_LEFT);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
+ BackEvent.EDGE_LEFT);
verify(mIOnBackInvokedCallback).onBackStarted();
}
+ @Test
+ public void animationDisabledFromSettings() throws RemoteException {
+ // Toggle the setting off
+ Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
+ mController = new BackAnimationController(
+ mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
+ mActivityTaskManager, mContext,
+ mContentResolver);
+ mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
+
+ RemoteAnimationTarget animationTarget = createAnimationTarget();
+ IOnBackInvokedCallback appCallback = mock(IOnBackInvokedCallback.class);
+ ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
+ createNavigationInfo(animationTarget, null, null,
+ BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback);
+
+ triggerBackGesture();
+
+ verify(appCallback, never()).onBackStarted();
+ verify(appCallback, never()).onBackProgressed(backEventCaptor.capture());
+ verify(appCallback, times(1)).onBackInvoked();
+
+ verify(mIOnBackInvokedCallback, never()).onBackStarted();
+ verify(mIOnBackInvokedCallback, never()).onBackProgressed(backEventCaptor.capture());
+ verify(mIOnBackInvokedCallback, never()).onBackInvoked();
+ }
+
private void doMotionEvent(int actionDown, int coordinate) {
mController.onMotionEvent(
MotionEvent.obtain(0, mEventTime, actionDown, coordinate, coordinate, 0),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
new file mode 100644
index 000000000000..44ff35466ae2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandlerTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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.bubbles;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.floatThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test {@link MotionEvent} handling in {@link BubblesNavBarMotionEventHandler}.
+ * Verifies that swipe events
+ */
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner.class)
+public class BubblesNavBarMotionEventHandlerTest extends ShellTestCase {
+
+ private BubblesNavBarMotionEventHandler mMotionEventHandler;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private Runnable mInterceptTouchRunnable;
+ @Mock
+ private MotionEventListener mMotionEventListener;
+ private long mMotionEventTime;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
+ mWindowManager);
+ mMotionEventHandler = new BubblesNavBarMotionEventHandler(getContext(), positioner,
+ mInterceptTouchRunnable, mMotionEventListener);
+ mMotionEventTime = SystemClock.uptimeMillis();
+ }
+
+ @Test
+ public void testMotionEvent_swipeUpInGestureZone_handled() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 690));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 490));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 390));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 390));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onMove(0, -300);
+ verify(mMotionEventListener).onMove(0, -500);
+ verify(mMotionEventListener).onMove(0, -600);
+ // Check that velocity up is about 5000
+ verify(mMotionEventListener).onUp(eq(0f), floatThat(f -> Math.round(f) == -5000));
+ verifyZeroInteractions(mMotionEventListener);
+ verify(mInterceptTouchRunnable).run();
+ }
+
+ @Test
+ public void testMotionEvent_swipeUpOutsideGestureZone_ignored() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 500));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 100));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 100));
+
+ verifyZeroInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ @Test
+ public void testMotionEvent_horizontalMoveMoreThanTouchSlop_handled() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 100, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 100, 990));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onMove(100, 0);
+ verify(mMotionEventListener).onUp(0, 0);
+ verifyZeroInteractions(mMotionEventListener);
+ verify(mInterceptTouchRunnable).run();
+ }
+
+ @Test
+ public void testMotionEvent_moveLessThanTouchSlop_ignored() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_MOVE, 0, 989));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_UP, 0, 989));
+
+ verify(mMotionEventListener).onDown(0, 990);
+ verifyNoMoreInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ @Test
+ public void testMotionEvent_actionCancel_listenerNotified() {
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_DOWN, 0, 990));
+ mMotionEventHandler.onMotionEvent(newEvent(ACTION_CANCEL, 0, 990));
+ verify(mMotionEventListener).onDown(0, 990);
+ verify(mMotionEventListener).onCancel();
+ verifyNoMoreInteractions(mMotionEventListener);
+ verifyZeroInteractions(mInterceptTouchRunnable);
+ }
+
+ private MotionEvent newEvent(int actionDown, float x, float y) {
+ MotionEvent event = MotionEvent.obtain(0L, mMotionEventTime, actionDown, x, y, 0);
+ mMotionEventTime += 10;
+ return event;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
new file mode 100644
index 000000000000..21887c03833a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 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.bubbles.animation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubbleExpandedView;
+import com.android.wm.shell.bubbles.TestableBubblePositioner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class ExpandedViewAnimationControllerTest extends ShellTestCase {
+
+ private ExpandedViewAnimationController mController;
+
+ @Mock
+ private WindowManager mWindowManager;
+
+ @Mock
+ private BubbleExpandedView mMockExpandedView;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ TestableBubblePositioner positioner = new TestableBubblePositioner(getContext(),
+ mWindowManager);
+ mController = new ExpandedViewAnimationControllerImpl(getContext(), positioner);
+
+ mController.setExpandedView(mMockExpandedView);
+ when(mMockExpandedView.getContentHeight()).thenReturn(1000);
+ }
+
+ @Test
+ public void testUpdateDrag_expandedViewMovesUpAndClipped() {
+ // Drag by 50 pixels which corresponds to 10 pixels with overscroll
+ int dragDistance = 50;
+ int dampenedDistance = 10;
+
+ mController.updateDrag(dragDistance);
+
+ verify(mMockExpandedView).setTopClip(dampenedDistance);
+ verify(mMockExpandedView).setContentTranslationY(-dampenedDistance);
+ verify(mMockExpandedView).setManageButtonTranslationY(-dampenedDistance);
+ }
+
+ @Test
+ public void testUpdateDrag_zOrderUpdates() {
+ mController.updateDrag(10);
+ mController.updateDrag(20);
+
+ verify(mMockExpandedView, times(1)).setSurfaceZOrderedOnTop(true);
+ verify(mMockExpandedView, times(1)).setAnimating(true);
+ }
+
+ @Test
+ public void testUpdateDrag_moveBackToZero_zOrderRestored() {
+ mController.updateDrag(50);
+ reset(mMockExpandedView);
+ mController.updateDrag(0);
+ mController.updateDrag(0);
+
+ verify(mMockExpandedView, times(1)).setSurfaceZOrderedOnTop(false);
+ verify(mMockExpandedView, times(1)).setAnimating(false);
+ }
+
+ @Test
+ public void testUpdateDrag_hapticFeedbackOnlyOnce() {
+ // Drag by 10 which is below the collapse threshold - no feedback
+ mController.updateDrag(10);
+ verify(mMockExpandedView, times(0)).performHapticFeedback(anyInt());
+ // 150 takes it over the threshold - perform feedback
+ mController.updateDrag(150);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ // Continue dragging, no more feedback
+ mController.updateDrag(200);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ // Drag below threshold and over again - no more feedback
+ mController.updateDrag(10);
+ mController.updateDrag(150);
+ verify(mMockExpandedView, times(1)).performHapticFeedback(anyInt());
+ }
+
+ @Test
+ public void testShouldCollapse_doNotCollapseIfNotDragged() {
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void testShouldCollapse_doNotCollapseIfVelocityDown() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(getVelocityAboveMinFling());
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void tesShouldCollapse_doNotCollapseIfVelocityUpIsSmall() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(-getVelocityBelowMinFling());
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ @Test
+ public void testShouldCollapse_collapseIfVelocityUpIsLarge() {
+ assumeTrue("Min fling velocity should be > 1 for this test", getMinFlingVelocity() > 1);
+ mController.setSwipeVelocity(-getVelocityAboveMinFling());
+ assertThat(mController.shouldCollapse()).isTrue();
+ }
+
+ @Test
+ public void testShouldCollapse_collapseIfPastThreshold() {
+ mController.updateDrag(500);
+ assertThat(mController.shouldCollapse()).isTrue();
+ }
+
+ @Test
+ public void testReset() {
+ mController.updateDrag(100);
+ reset(mMockExpandedView);
+ mController.reset();
+ verify(mMockExpandedView, atLeastOnce()).setAnimating(false);
+ verify(mMockExpandedView).setContentAlpha(1);
+ verify(mMockExpandedView).setAlpha(1);
+ verify(mMockExpandedView).setManageButtonAlpha(1);
+ verify(mMockExpandedView).setManageButtonAlpha(1);
+ verify(mMockExpandedView).setTopClip(0);
+ verify(mMockExpandedView).setContentTranslationY(-0f);
+ verify(mMockExpandedView).setManageButtonTranslationY(-0f);
+ verify(mMockExpandedView).setBottomClip(0);
+ verify(mMockExpandedView).movePointerBy(0, 0);
+ assertThat(mController.shouldCollapse()).isFalse();
+ }
+
+ private int getVelocityBelowMinFling() {
+ return getMinFlingVelocity() - 1;
+ }
+
+ private int getVelocityAboveMinFling() {
+ return getMinFlingVelocity() + 1;
+ }
+
+ private int getMinFlingVelocity() {
+ return ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index ecf1c5d41864..6a6db8aa3c04 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -345,8 +345,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -358,8 +358,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -371,8 +371,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
true);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
@@ -384,8 +384,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
false);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
- mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
- Surface.ROTATION_90, handlerWCT);
+ mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index df18133adcfb..abd55dd7d606 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -76,6 +76,7 @@ public class PipControllerTest extends ShellTestCase {
@Mock private PhonePipMenuController mMockPhonePipMenuController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
+ @Mock private PipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
@Mock private PipSnapAlgorithm mMockPipSnapAlgorithm;
@Mock private PipMediaController mMockPipMediaController;
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@@ -101,7 +102,8 @@ public class PipControllerTest extends ShellTestCase {
}).when(mMockExecutor).execute(any());
mPipController = new PipController(mContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
- mMockPipBoundsState, mMockPipMediaController,
+ mMockPipKeepClearAlgorithm,
+ mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mPipParamsChangedForwarder,
@@ -134,7 +136,8 @@ public class PipControllerTest extends ShellTestCase {
assertNull(PipController.create(spyContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
- mMockPipBoundsState, mMockPipMediaController,
+ mMockPipKeepClearAlgorithm,
+ mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mPipParamsChangedForwarder,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
new file mode 100644
index 000000000000..e0f7e35f8d02
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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.pip.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+/**
+ * Unit tests against {@link PipKeepClearAlgorithm}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class PipKeepClearAlgorithmTest extends ShellTestCase {
+
+ private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+ private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
+
+ @Before
+ public void setUp() throws Exception {
+ mPipKeepClearAlgorithm = new PipKeepClearAlgorithm();
+ }
+
+ @Test
+ public void adjust_withCollidingRestrictedKeepClearAreas_movesBounds() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
+ Set.of(), DISPLAY_BOUNDS);
+
+ assertFalse(outBounds.contains(keepClearRect));
+ }
+
+ @Test
+ public void adjust_withNonCollidingRestrictedKeepClearAreas_boundsDoNotChange() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
+ Set.of(), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_withCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ // TODO(b/183746978): update this test to accommodate for the updated algorithm
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ Set.of(keepClearRect), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_withNonCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ Set.of(keepClearRect), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 50f6bd7b4927..9ef8c322d105 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -30,11 +30,13 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static java.lang.Integer.MAX_VALUE;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.view.SurfaceControl;
@@ -77,6 +79,7 @@ public class RecentTasksControllerTest extends ShellTestCase {
@Before
public void setUp() {
mMainExecutor = new TestShellExecutor();
+ when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
mRecentTasksController = spy(new RecentTasksController(mContext, mTaskStackListener,
mMainExecutor));
mShellTaskOrganizer = new ShellTaskOrganizer(mMainExecutor, mContext,
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 ffaab652aa99..b52690487944 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
@@ -340,7 +340,7 @@ public class SplitTransitionTests extends ShellTestCase {
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
- IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+ IBinder transition = mSplitScreenTransitions.startDismissTransition(
new WindowContainerTransaction(), mStageCoordinator,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, STAGE_TYPE_SIDE);
boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -363,7 +363,7 @@ public class SplitTransitionTests extends ShellTestCase {
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
- IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+ IBinder transition = mSplitScreenTransitions.startDismissTransition(
new WindowContainerTransaction(), mStageCoordinator, EXIT_REASON_DRAG_DIVIDER,
STAGE_TYPE_SIDE);
mMainStage.onTaskVanished(mMainChild);
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index c80fb188e70f..779c4b75efc4 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -33,6 +33,7 @@ license {
cc_defaults {
name: "libandroidfw_defaults",
+ cpp_std: "gnu++2b",
cflags: [
"-Werror",
"-Wunreachable-code",
@@ -60,6 +61,7 @@ cc_library {
"AssetManager2.cpp",
"AssetsProvider.cpp",
"AttributeResolution.cpp",
+ "BigBuffer.cpp",
"ChunkIterator.cpp",
"ConfigDescription.cpp",
"Idmap.cpp",
@@ -72,6 +74,7 @@ cc_library {
"ResourceTypes.cpp",
"ResourceUtils.cpp",
"StreamingZipInflater.cpp",
+ "StringPool.cpp",
"TypeWrappers.cpp",
"Util.cpp",
"ZipFileRO.cpp",
@@ -161,6 +164,7 @@ cc_test {
"tests/AssetManager2_test.cpp",
"tests/AttributeFinder_test.cpp",
"tests/AttributeResolution_test.cpp",
+ "tests/BigBuffer_test.cpp",
"tests/ByteBucketArray_test.cpp",
"tests/Config_test.cpp",
"tests/ConfigDescription_test.cpp",
@@ -173,6 +177,7 @@ cc_test {
"tests/ResTable_test.cpp",
"tests/Split_test.cpp",
"tests/StringPiece_test.cpp",
+ "tests/StringPool_test.cpp",
"tests/Theme_test.cpp",
"tests/TypeWrappers_test.cpp",
"tests/ZipUtils_test.cpp",
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 136fc6ca4e2a..39c7d198fe5b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -601,6 +601,10 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
return base::unexpected(result.error());
}
+ if (type_idx == 0x1c) {
+ LOG(ERROR) << base::StringPrintf("foobar first result %s", result->package_name->c_str());
+ }
+
bool overlaid = false;
if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
for (const auto& id_map : package_group.overlays_) {
diff --git a/tools/aapt2/util/BigBuffer.cpp b/libs/androidfw/BigBuffer.cpp
index 75fa78915b65..bedfc49a1b0d 100644
--- a/tools/aapt2/util/BigBuffer.cpp
+++ b/libs/androidfw/BigBuffer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "util/BigBuffer.h"
+#include <androidfw/BigBuffer.h>
#include <algorithm>
#include <memory>
@@ -22,7 +22,7 @@
#include "android-base/logging.h"
-namespace aapt {
+namespace android {
void* BigBuffer::NextBlockImpl(size_t size) {
if (!blocks_.empty()) {
@@ -84,4 +84,4 @@ std::string BigBuffer::to_string() const {
return result;
}
-} // namespace aapt
+} // namespace android
diff --git a/tools/aapt2/StringPool.cpp b/libs/androidfw/StringPool.cpp
index 8eabd3225d87..b59e906f6281 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/libs/androidfw/StringPool.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include "StringPool.h"
+#include <androidfw/BigBuffer.h>
+#include <androidfw/StringPool.h>
#include <algorithm>
#include <memory>
@@ -23,15 +24,14 @@
#include "android-base/logging.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
-
-#include "util/BigBuffer.h"
-#include "util/Util.h"
+#include "androidfw/Util.h"
using ::android::StringPiece;
-namespace aapt {
+namespace android {
-StringPool::Ref::Ref() : entry_(nullptr) {}
+StringPool::Ref::Ref() : entry_(nullptr) {
+}
StringPool::Ref::Ref(const StringPool::Ref& rhs) : entry_(rhs.entry_) {
if (entry_ != nullptr) {
@@ -88,10 +88,10 @@ const StringPool::Context& StringPool::Ref::GetContext() const {
return entry_->context;
}
-StringPool::StyleRef::StyleRef() : entry_(nullptr) {}
+StringPool::StyleRef::StyleRef() : entry_(nullptr) {
+}
-StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs)
- : entry_(rhs.entry_) {
+StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs) : entry_(rhs.entry_) {
if (entry_ != nullptr) {
entry_->ref_++;
}
@@ -210,7 +210,7 @@ StringPool::StyleRef StringPool::MakeRef(const StyleString& str, const Context&
entry->context = context;
entry->index_ = styles_.size();
entry->ref_ = 0;
- for (const aapt::Span& span : str.spans) {
+ for (const android::Span& span : str.spans) {
entry->spans.emplace_back(Span{MakeRef(span.name), span.first_char, span.last_char});
}
@@ -368,24 +368,23 @@ static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out
IDiagnostics* diag) {
if (utf8) {
const std::string& encoded = util::Utf8ToModifiedUtf8(str);
- const ssize_t utf16_length = utf8_to_utf16_length(
- reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
+ const ssize_t utf16_length =
+ utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
CHECK(utf16_length >= 0);
// Make sure the lengths to be encoded do not exceed the maximum length that
// can be encoded using chars
- if ((((size_t)encoded.size()) > EncodeLengthMax<char>())
- || (((size_t)utf16_length) > EncodeLengthMax<char>())) {
-
+ if ((((size_t)encoded.size()) > EncodeLengthMax<char>()) ||
+ (((size_t)utf16_length) > EncodeLengthMax<char>())) {
diag->Error(DiagMessage() << "string too large to encode using UTF-8 "
- << "written instead as '" << kStringTooLarge << "'");
+ << "written instead as '" << kStringTooLarge << "'");
EncodeString(kStringTooLarge, utf8, out, diag);
return false;
}
- const size_t total_size = EncodedLengthUnits<char>(utf16_length)
- + EncodedLengthUnits<char>(encoded.size()) + encoded.size() + 1;
+ const size_t total_size = EncodedLengthUnits<char>(utf16_length) +
+ EncodedLengthUnits<char>(encoded.size()) + encoded.size() + 1;
char* data = out->NextBlock<char>(total_size);
@@ -404,15 +403,14 @@ static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out
// length that can be encoded
if (((size_t)utf16_length) > EncodeLengthMax<char16_t>()) {
diag->Error(DiagMessage() << "string too large to encode using UTF-16 "
- << "written instead as '" << kStringTooLarge << "'");
+ << "written instead as '" << kStringTooLarge << "'");
EncodeString(kStringTooLarge, utf8, out, diag);
return false;
}
// Total number of 16-bit words to write.
- const size_t total_size = EncodedLengthUnits<char16_t>(utf16_length)
- + encoded.size() + 1;
+ const size_t total_size = EncodedLengthUnits<char16_t>(utf16_length) + encoded.size() + 1;
char16_t* data = out->NextBlock<char16_t>(total_size);
@@ -431,8 +429,7 @@ static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out
return true;
}
-bool StringPool::Flatten(BigBuffer* out, const StringPool& pool, bool utf8,
- IDiagnostics* diag) {
+bool StringPool::Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag) {
bool no_error = true;
const size_t start_index = out->size();
android::ResStringPool_header* header = out->NextBlock<android::ResStringPool_header>();
@@ -490,8 +487,8 @@ bool StringPool::Flatten(BigBuffer* out, const StringPool& pool, bool utf8,
// ResStringPool_span structure worth of 0xFFFFFFFF at the end
// of the style block, so fill in the remaining 2 32bit words
// with 0xFFFFFFFF.
- const size_t padding_length = sizeof(android::ResStringPool_span) -
- sizeof(android::ResStringPool_span::name);
+ const size_t padding_length =
+ sizeof(android::ResStringPool_span) - sizeof(android::ResStringPool_span::name);
uint8_t* padding = out->NextBlock<uint8_t>(padding_length);
memset(padding, 0xff, padding_length);
out->Align4();
@@ -508,4 +505,4 @@ bool StringPool::FlattenUtf16(BigBuffer* out, const StringPool& pool, IDiagnosti
return Flatten(out, pool, false, diag);
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp
index 59c9d640bb91..be9edc430871 100644
--- a/libs/androidfw/Util.cpp
+++ b/libs/androidfw/Util.cpp
@@ -68,6 +68,107 @@ std::string Utf16ToUtf8(const StringPiece16& utf16) {
return utf8;
}
+std::string Utf8ToModifiedUtf8(const std::string& utf8) {
+ // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
+ // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
+ // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
+ // codepoints replaced with 2 3 byte surrogate pairs
+ size_t modified_size = 0;
+ const size_t size = utf8.size();
+ for (size_t i = 0; i < size; i++) {
+ if (((uint8_t)utf8[i] >> 4) == 0xF) {
+ modified_size += 6;
+ i += 3;
+ } else {
+ modified_size++;
+ }
+ }
+
+ // Early out if no 4 byte codepoints are found
+ if (size == modified_size) {
+ return utf8;
+ }
+
+ std::string output;
+ output.reserve(modified_size);
+ for (size_t i = 0; i < size; i++) {
+ if (((uint8_t)utf8[i] >> 4) == 0xF) {
+ int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr);
+
+ // Calculate the high and low surrogates as UTF-16 would
+ int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
+ int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
+
+ // Encode each surrogate in UTF-8
+ output.push_back((char)(0xE4 | ((high >> 12) & 0xF)));
+ output.push_back((char)(0x80 | ((high >> 6) & 0x3F)));
+ output.push_back((char)(0x80 | (high & 0x3F)));
+ output.push_back((char)(0xE4 | ((low >> 12) & 0xF)));
+ output.push_back((char)(0x80 | ((low >> 6) & 0x3F)));
+ output.push_back((char)(0x80 | (low & 0x3F)));
+ i += 3;
+ } else {
+ output.push_back(utf8[i]);
+ }
+ }
+
+ return output;
+}
+
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
+ // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
+ // representation.
+ std::string output;
+ output.reserve(modified_utf8.size());
+
+ size_t index = 0;
+ const size_t modified_size = modified_utf8.size();
+ while (index < modified_size) {
+ size_t next_index;
+ int32_t high_surrogate =
+ utf32_from_utf8_at(modified_utf8.data(), modified_size, index, &next_index);
+ if (high_surrogate < 0) {
+ return {};
+ }
+
+ // Check that the first codepoint is within the high surrogate range
+ if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) {
+ int32_t low_surrogate =
+ utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index, &next_index);
+ if (low_surrogate < 0) {
+ return {};
+ }
+
+ // Check that the second codepoint is within the low surrogate range
+ if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) {
+ const char32_t codepoint =
+ (char32_t)(((high_surrogate - 0xD800) * 0x400) + (low_surrogate - 0xDC00) + 0x10000);
+
+ // The decoded codepoint should represent a 4 byte, UTF-8 character
+ const size_t utf8_length = (size_t)utf32_to_utf8_length(&codepoint, 1);
+ if (utf8_length != 4) {
+ return {};
+ }
+
+ // Encode the UTF-8 representation of the codepoint into the string
+ char* start = &output[output.size()];
+ output.resize(output.size() + utf8_length);
+ utf32_to_utf8((char32_t*)&codepoint, 1, start, utf8_length + 1);
+
+ index = next_index;
+ continue;
+ }
+ }
+
+ // Append non-surrogate pairs to the output string
+ for (size_t i = index; i < next_index; i++) {
+ output.push_back(modified_utf8[i]);
+ }
+ index = next_index;
+ }
+ return output;
+}
+
static std::vector<std::string> SplitAndTransform(
const StringPiece& str, char sep, const std::function<char(char)>& f) {
std::vector<std::string> parts;
@@ -90,6 +191,29 @@ std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep) {
return SplitAndTransform(str, sep, ::tolower);
}
+std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer) {
+ std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
+ uint8_t* p = data.get();
+ for (const auto& block : buffer) {
+ memcpy(p, block.buffer.get(), block.size);
+ p += block.size;
+ }
+ return data;
+}
+
+StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
+ if (auto str = pool.stringAt(idx); str.ok()) {
+ return *str;
+ }
+ return StringPiece16();
+}
+
+std::string GetString(const android::ResStringPool& pool, size_t idx) {
+ if (auto str = pool.string8At(idx); str.ok()) {
+ return ModifiedUtf8ToUtf8(str->to_string());
+ }
+ return Utf16ToUtf8(GetString16(pool, idx));
+}
} // namespace util
} // namespace android
diff --git a/tools/aapt2/util/BigBuffer.h b/libs/androidfw/include/androidfw/BigBuffer.h
index d4b3abce68a7..b99a4edf9d88 100644
--- a/tools/aapt2/util/BigBuffer.h
+++ b/libs/androidfw/include/androidfw/BigBuffer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_BIG_BUFFER_H
-#define AAPT_BIG_BUFFER_H
+#ifndef _ANDROID_BIG_BUFFER_H
+#define _ANDROID_BIG_BUFFER_H
#include <cstring>
#include <memory>
@@ -26,7 +26,7 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
-namespace aapt {
+namespace android {
/**
* Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
@@ -133,22 +133,24 @@ class BigBuffer {
std::vector<Block> blocks_;
};
-inline BigBuffer::BigBuffer(size_t block_size)
- : block_size_(block_size), size_(0) {}
+inline BigBuffer::BigBuffer(size_t block_size) : block_size_(block_size), size_(0) {
+}
inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept
- : block_size_(rhs.block_size_),
- size_(rhs.size_),
- blocks_(std::move(rhs.blocks_)) {}
+ : block_size_(rhs.block_size_), size_(rhs.size_), blocks_(std::move(rhs.blocks_)) {
+}
-inline size_t BigBuffer::size() const { return size_; }
+inline size_t BigBuffer::size() const {
+ return size_;
+}
-inline size_t BigBuffer::block_size() const { return block_size_; }
+inline size_t BigBuffer::block_size() const {
+ return block_size_;
+}
template <typename T>
inline T* BigBuffer::NextBlock(size_t count) {
- static_assert(std::is_standard_layout<T>::value,
- "T must be standard_layout type");
+ static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
CHECK(count != 0);
return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count));
}
@@ -160,14 +162,15 @@ inline void BigBuffer::BackUp(size_t count) {
}
inline void BigBuffer::AppendBuffer(BigBuffer&& buffer) {
- std::move(buffer.blocks_.begin(), buffer.blocks_.end(),
- std::back_inserter(blocks_));
+ std::move(buffer.blocks_.begin(), buffer.blocks_.end(), std::back_inserter(blocks_));
size_ += buffer.size_;
buffer.blocks_.clear();
buffer.size_ = 0;
}
-inline void BigBuffer::Pad(size_t bytes) { NextBlock<char>(bytes); }
+inline void BigBuffer::Pad(size_t bytes) {
+ NextBlock<char>(bytes);
+}
inline void BigBuffer::Align4() {
const size_t unaligned = size_ % 4;
@@ -184,6 +187,6 @@ inline BigBuffer::const_iterator BigBuffer::end() const {
return blocks_.end();
}
-} // namespace aapt
+} // namespace android
-#endif // AAPT_BIG_BUFFER_H
+#endif // _ANDROID_BIG_BUFFER_H
diff --git a/libs/androidfw/include/androidfw/IDiagnostics.h b/libs/androidfw/include/androidfw/IDiagnostics.h
new file mode 100644
index 000000000000..273b05ac7689
--- /dev/null
+++ b/libs/androidfw/include/androidfw/IDiagnostics.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef _ANDROID_DIAGNOSTICS_H
+#define _ANDROID_DIAGNOSTICS_H
+
+#include <sstream>
+#include <string>
+
+#include "Source.h"
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+namespace android {
+
+struct DiagMessageActual {
+ Source source;
+ std::string message;
+};
+
+struct DiagMessage {
+ public:
+ DiagMessage() = default;
+
+ explicit DiagMessage(const android::StringPiece& src) : source_(src) {
+ }
+
+ explicit DiagMessage(const Source& src) : source_(src) {
+ }
+
+ explicit DiagMessage(size_t line) : source_(Source().WithLine(line)) {
+ }
+
+ template <typename T>
+ DiagMessage& operator<<(const T& value) {
+ message_ << value;
+ return *this;
+ }
+
+ DiagMessageActual Build() const {
+ return DiagMessageActual{source_, message_.str()};
+ }
+
+ private:
+ Source source_;
+ std::stringstream message_;
+};
+
+template <>
+inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
+ message_ << android::StringPiece16(value);
+ return *this;
+}
+
+struct IDiagnostics {
+ virtual ~IDiagnostics() = default;
+
+ enum class Level { Note, Warn, Error };
+
+ virtual void Log(Level level, DiagMessageActual& actualMsg) = 0;
+
+ virtual void Error(const DiagMessage& message) {
+ DiagMessageActual actual = message.Build();
+ Log(Level::Error, actual);
+ }
+
+ virtual void Warn(const DiagMessage& message) {
+ DiagMessageActual actual = message.Build();
+ Log(Level::Warn, actual);
+ }
+
+ virtual void Note(const DiagMessage& message) {
+ DiagMessageActual actual = message.Build();
+ Log(Level::Note, actual);
+ }
+};
+
+class SourcePathDiagnostics : public IDiagnostics {
+ public:
+ SourcePathDiagnostics(const Source& src, IDiagnostics* diag) : source_(src), diag_(diag) {
+ }
+
+ void Log(Level level, DiagMessageActual& actual_msg) override {
+ actual_msg.source.path = source_.path;
+ diag_->Log(level, actual_msg);
+ if (level == Level::Error) {
+ error = true;
+ }
+ }
+
+ bool HadError() {
+ return error;
+ }
+
+ private:
+ Source source_;
+ IDiagnostics* diag_;
+ bool error = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
+};
+
+class NoOpDiagnostics : public IDiagnostics {
+ public:
+ NoOpDiagnostics() = default;
+
+ void Log(Level level, DiagMessageActual& actual_msg) override {
+ (void)level;
+ (void)actual_msg;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(NoOpDiagnostics);
+};
+
+} // namespace android
+
+#endif /* _ANDROID_DIAGNOSTICS_H */
diff --git a/tools/aapt2/Source.h b/libs/androidfw/include/androidfw/Source.h
index 4f9369a5d517..0421a91d3eba 100644
--- a/tools/aapt2/Source.h
+++ b/libs/androidfw/include/androidfw/Source.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_SOURCE_H
-#define AAPT_SOURCE_H
+#ifndef _ANDROID_SOURCE_H
+#define _ANDROID_SOURCE_H
#include <optional>
#include <ostream>
@@ -24,7 +24,7 @@
#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
-namespace aapt {
+namespace android {
// Represents a file on disk. Used for logging and showing errors.
struct Source {
@@ -38,10 +38,12 @@ struct Source {
}
inline Source(const android::StringPiece& path, const android::StringPiece& archive)
- : path(path.to_string()), archive(archive.to_string()) {}
+ : path(path.to_string()), archive(archive.to_string()) {
+ }
inline Source(const android::StringPiece& path, size_t line)
- : path(path.to_string()), line(line) {}
+ : path(path.to_string()), line(line) {
+ }
inline Source WithLine(size_t line) const {
return Source(path, line);
@@ -84,6 +86,6 @@ inline bool operator<(const Source& lhs, const Source& rhs) {
return bool(rhs.line);
}
-} // namespace aapt
+} // namespace android
-#endif // AAPT_SOURCE_H
+#endif // _ANDROID_SOURCE_H
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
index 921877dc4982..fac2fa4fa575 100644
--- a/libs/androidfw/include/androidfw/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -288,12 +288,12 @@ inline ::std::basic_string<TChar>& operator+=(::std::basic_string<TChar>& lhs,
template <typename TChar>
inline bool operator==(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
- return rhs == lhs;
+ return BasicStringPiece<TChar>(lhs) == rhs;
}
template <typename TChar>
inline bool operator!=(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
- return rhs != lhs;
+ return BasicStringPiece<TChar>(lhs) != rhs;
}
} // namespace android
diff --git a/tools/aapt2/StringPool.h b/libs/androidfw/include/androidfw/StringPool.h
index 3457e0b41859..25174d8fe3c8 100644
--- a/tools/aapt2/StringPool.h
+++ b/libs/androidfw/include/androidfw/StringPool.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_STRING_POOL_H
-#define AAPT_STRING_POOL_H
+#ifndef _ANDROID_STRING_POOL_H
+#define _ANDROID_STRING_POOL_H
#include <functional>
#include <memory>
@@ -23,14 +23,13 @@
#include <unordered_map>
#include <vector>
+#include "BigBuffer.h"
+#include "IDiagnostics.h"
#include "android-base/macros.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
-#include "Diagnostics.h"
-#include "util/BigBuffer.h"
-
-namespace aapt {
+namespace android {
struct Span {
std::string name;
@@ -67,8 +66,10 @@ class StringPool {
android::ConfigDescription config;
Context() = default;
- Context(uint32_t p, const android::ConfigDescription& c) : priority(p), config(c) {}
- explicit Context(uint32_t p) : priority(p) {}
+ Context(uint32_t p, const android::ConfigDescription& c) : priority(p), config(c) {
+ }
+ explicit Context(uint32_t p) : priority(p) {
+ }
explicit Context(const android::ConfigDescription& c) : priority(kNormalPriority), config(c) {
}
};
@@ -222,6 +223,6 @@ class StringPool {
std::unordered_multimap<android::StringPiece, Entry*> indexed_strings_;
};
-} // namespace aapt
+} // namespace android
-#endif // AAPT_STRING_POOL_H
+#endif // _ANDROID_STRING_POOL_H
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index c59b5b6c51a2..1bbc7f5716bc 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -17,15 +17,18 @@
#ifndef UTIL_H_
#define UTIL_H_
+#include <android-base/macros.h>
+#include <util/map_ptr.h>
+
#include <cstdlib>
#include <memory>
#include <sstream>
#include <vector>
-#include <android-base/macros.h>
-#include <util/map_ptr.h>
-
+#include "androidfw/BigBuffer.h"
+#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+#include "utils/ByteOrder.h"
#ifdef __ANDROID__
#define ANDROID_LOG(x) LOG(x)
@@ -125,6 +128,28 @@ std::u16string Utf8ToUtf16(const StringPiece& utf8);
// Converts a UTF-16 string to a UTF-8 string.
std::string Utf16ToUtf8(const StringPiece16& utf16);
+// Converts a UTF8 string into Modified UTF8
+std::string Utf8ToModifiedUtf8(const std::string& utf8);
+
+// Converts a Modified UTF8 string into a UTF8 string
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
+
+inline uint16_t HostToDevice16(uint16_t value) {
+ return htods(value);
+}
+
+inline uint32_t HostToDevice32(uint32_t value) {
+ return htodl(value);
+}
+
+inline uint16_t DeviceToHost16(uint16_t value) {
+ return dtohs(value);
+}
+
+inline uint32_t DeviceToHost32(uint32_t value) {
+ return dtohl(value);
+}
+
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
template <typename T>
@@ -136,6 +161,18 @@ inline bool IsFourByteAligned(const void* data) {
return ((size_t)data & 0x3U) == 0;
}
+// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
+// the conversion to UTF-16 happens within ResStringPool.
+android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
+
+// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
+// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
+// which maintains no state or cache. This means we must return an std::string copy.
+std::string GetString(const android::ResStringPool& pool, size_t idx);
+
+// Copies the entire BigBuffer into a single buffer.
+std::unique_ptr<uint8_t[]> Copy(const android::BigBuffer& buffer);
+
} // namespace util
} // namespace android
diff --git a/tools/aapt2/util/BigBuffer_test.cpp b/libs/androidfw/tests/BigBuffer_test.cpp
index 64dcc1dad9a2..382d21e20846 100644
--- a/tools/aapt2/util/BigBuffer_test.cpp
+++ b/libs/androidfw/tests/BigBuffer_test.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include "util/BigBuffer.h"
+#include "androidfw/BigBuffer.h"
-#include "test/Test.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
using ::testing::NotNull;
-namespace aapt {
+namespace android {
TEST(BigBufferTest, AllocateSingleBlock) {
BigBuffer buffer(4);
@@ -62,7 +63,7 @@ TEST(BigBufferTest, AppendAndMoveBlock) {
*b1 = 44;
buffer.AppendBuffer(std::move(buffer2));
- EXPECT_EQ(0u, buffer2.size()); // NOLINT
+ EXPECT_EQ(0u, buffer2.size()); // NOLINT
EXPECT_EQ(buffer2.begin(), buffer2.end());
}
@@ -97,4 +98,4 @@ TEST(BigBufferTest, PadAndAlignProperly) {
ASSERT_EQ(8u, buffer.size());
}
-} // namespace aapt
+} // namespace android
diff --git a/tools/aapt2/StringPool_test.cpp b/libs/androidfw/tests/StringPool_test.cpp
index 6e5200bca44c..047d45785409 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/libs/androidfw/tests/StringPool_test.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
#include <string>
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
-#include "test/Test.h"
-#include "util/Util.h"
+#include "androidfw/Util.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
using ::android::StringPiece;
using ::android::StringPiece16;
@@ -31,7 +31,7 @@ using ::testing::Ne;
using ::testing::NotNull;
using ::testing::Pointee;
-namespace aapt {
+namespace android {
TEST(StringPoolTest, InsertOneString) {
StringPool pool;
@@ -176,8 +176,8 @@ TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
StringPool::Ref ref = pool.MakeRef("android");
- StyleString str{{"android"}};
- StringPool::StyleRef style_ref = pool.MakeRef(StyleString{{"android"}});
+ StyleString str{{"android"}, {}};
+ StringPool::StyleRef style_ref = pool.MakeRef(StyleString{{"android"}, {}});
EXPECT_THAT(ref.index(), Ne(style_ref.index()));
}
@@ -185,9 +185,9 @@ TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
TEST(StringPoolTest, StylesAndStringsAreSeparateAfterSorting) {
StringPool pool;
- StringPool::StyleRef ref_a = pool.MakeRef(StyleString{{"beta"}});
+ StringPool::StyleRef ref_a = pool.MakeRef(StyleString{{"beta"}, {}});
StringPool::Ref ref_b = pool.MakeRef("alpha");
- StringPool::StyleRef ref_c = pool.MakeRef(StyleString{{"alpha"}});
+ StringPool::StyleRef ref_c = pool.MakeRef(StyleString{{"alpha"}, {}});
EXPECT_THAT(ref_b.index(), Ne(ref_c.index()));
@@ -200,27 +200,27 @@ TEST(StringPoolTest, StylesAndStringsAreSeparateAfterSorting) {
TEST(StringPoolTest, FlattenEmptyStringPoolUtf8) {
using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
+ NoOpDiagnostics diag;
StringPool pool;
BigBuffer buffer(1024);
StringPool::FlattenUtf8(&buffer, pool, &diag);
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
ResStringPool test;
ASSERT_THAT(test.setTo(data.get(), buffer.size()), Eq(NO_ERROR));
}
TEST(StringPoolTest, FlattenOddCharactersUtf16) {
using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
+ NoOpDiagnostics diag;
StringPool pool;
pool.MakeRef("\u093f");
BigBuffer buffer(1024);
StringPool::FlattenUtf16(&buffer, pool, &diag);
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
auto str = test.stringAt(0);
@@ -239,7 +239,7 @@ constexpr const char* sLongString =
TEST(StringPoolTest, Flatten) {
using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
+ NoOpDiagnostics diag;
StringPool pool;
@@ -264,38 +264,38 @@ TEST(StringPoolTest, Flatten) {
// Test both UTF-8 and UTF-16 buffers.
for (const BigBuffer& buffer : buffers) {
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- EXPECT_THAT(util::GetString(test, 1), Eq("hello"));
- EXPECT_THAT(util::GetString16(test, 1), Eq(u"hello"));
+ EXPECT_THAT(android::util::GetString(test, 1), Eq("hello"));
+ EXPECT_THAT(android::util::GetString16(test, 1), Eq(u"hello"));
- EXPECT_THAT(util::GetString(test, 2), Eq("goodbye"));
- EXPECT_THAT(util::GetString16(test, 2), Eq(u"goodbye"));
+ EXPECT_THAT(android::util::GetString(test, 2), Eq("goodbye"));
+ EXPECT_THAT(android::util::GetString16(test, 2), Eq(u"goodbye"));
- EXPECT_THAT(util::GetString(test, 3), Eq(sLongString));
- EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
+ EXPECT_THAT(android::util::GetString(test, 3), Eq(sLongString));
+ EXPECT_THAT(android::util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
EXPECT_TRUE(test.stringAt(4).has_value() || test.string8At(4).has_value());
- EXPECT_THAT(util::GetString(test, 0), Eq("style"));
- EXPECT_THAT(util::GetString16(test, 0), Eq(u"style"));
+ EXPECT_THAT(android::util::GetString(test, 0), Eq("style"));
+ EXPECT_THAT(android::util::GetString16(test, 0), Eq(u"style"));
auto span_result = test.styleAt(0);
ASSERT_TRUE(span_result.has_value());
const ResStringPool_span* span = span_result->unsafe_ptr();
- EXPECT_THAT(util::GetString(test, span->name.index), Eq("b"));
- EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b"));
+ EXPECT_THAT(android::util::GetString(test, span->name.index), Eq("b"));
+ EXPECT_THAT(android::util::GetString16(test, span->name.index), Eq(u"b"));
EXPECT_THAT(span->firstChar, Eq(0u));
EXPECT_THAT(span->lastChar, Eq(1u));
span++;
ASSERT_THAT(span->name.index, Ne(ResStringPool_span::END));
- EXPECT_THAT(util::GetString(test, span->name.index), Eq("i"));
- EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"i"));
+ EXPECT_THAT(android::util::GetString(test, span->name.index), Eq("i"));
+ EXPECT_THAT(android::util::GetString16(test, span->name.index), Eq(u"i"));
EXPECT_THAT(span->firstChar, Eq(2u));
EXPECT_THAT(span->lastChar, Eq(3u));
span++;
@@ -306,15 +306,15 @@ TEST(StringPoolTest, Flatten) {
TEST(StringPoolTest, ModifiedUTF8) {
using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
+ NoOpDiagnostics diag;
StringPool pool;
- StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
- StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
+ StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
+ StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
BigBuffer buffer(1024);
StringPool::FlattenUtf8(&buffer, pool, &diag);
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
// Check that the codepoints are encoded using two three-byte surrogate pairs
ResStringPool test;
@@ -332,13 +332,13 @@ TEST(StringPoolTest, ModifiedUTF8) {
EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
// Check that retrieving the strings returns the original UTF-8 character bytes
- EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
- EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
- EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
+ EXPECT_THAT(android::util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
+ EXPECT_THAT(android::util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
+ EXPECT_THAT(android::util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
}
TEST(StringPoolTest, MaxEncodingLength) {
- StdErrDiagnostics diag;
+ NoOpDiagnostics diag;
using namespace android; // For NO_ERROR on Windows.
ResStringPool test;
@@ -348,15 +348,15 @@ TEST(StringPoolTest, MaxEncodingLength) {
// Make sure a UTF-8 string under the maximum length does not produce an error
EXPECT_THAT(StringPool::FlattenUtf8(&buffers[0], pool, &diag), Eq(true));
- std::unique_ptr<uint8_t[]> data = util::Copy(buffers[0]);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffers[0]);
test.setTo(data.get(), buffers[0].size());
- EXPECT_THAT(util::GetString(test, 0), Eq("aaaaaaaaaa"));
+ EXPECT_THAT(android::util::GetString(test, 0), Eq("aaaaaaaaaa"));
// Make sure a UTF-16 string under the maximum length does not produce an error
EXPECT_THAT(StringPool::FlattenUtf16(&buffers[1], pool, &diag), Eq(true));
- data = util::Copy(buffers[1]);
+ data = android::util::Copy(buffers[1]);
test.setTo(data.get(), buffers[1].size());
- EXPECT_THAT(util::GetString16(test, 0), Eq(u"aaaaaaaaaa"));
+ EXPECT_THAT(android::util::GetString16(test, 0), Eq(u"aaaaaaaaaa"));
StringPool pool2;
std::string longStr(50000, 'a');
@@ -368,11 +368,11 @@ TEST(StringPoolTest, MaxEncodingLength) {
// Make sure a string that exceeds the maximum length of UTF-8 produces an
// error and writes a shorter error string instead
EXPECT_THAT(StringPool::FlattenUtf8(&buffers2[0], pool2, &diag), Eq(false));
- data = util::Copy(buffers2[0]);
+ data = android::util::Copy(buffers2[0]);
test.setTo(data.get(), buffers2[0].size());
- EXPECT_THAT(util::GetString(test, 0), "this fits1");
- EXPECT_THAT(util::GetString(test, 1), "STRING_TOO_LARGE");
- EXPECT_THAT(util::GetString(test, 2), "this fits2");
+ EXPECT_THAT(android::util::GetString(test, 0), "this fits1");
+ EXPECT_THAT(android::util::GetString(test, 1), "STRING_TOO_LARGE");
+ EXPECT_THAT(android::util::GetString(test, 2), "this fits2");
// Make sure a string that a string that exceeds the maximum length of UTF-8
// but not UTF-16 does not error for UTF-16
@@ -380,9 +380,9 @@ TEST(StringPoolTest, MaxEncodingLength) {
std::u16string longStr16(50000, 'a');
pool3.MakeRef(longStr);
EXPECT_THAT(StringPool::FlattenUtf16(&buffers2[1], pool3, &diag), Eq(true));
- data = util::Copy(buffers2[1]);
+ data = android::util::Copy(buffers2[1]);
test.setTo(data.get(), buffers2[1].size());
- EXPECT_THAT(util::GetString16(test, 0), Eq(longStr16));
+ EXPECT_THAT(android::util::GetString16(test, 0), Eq(longStr16));
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index d5fee3f667a9..2e6e36a9ff22 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -16,7 +16,9 @@
#ifndef DEVICEINFO_H
#define DEVICEINFO_H
+#include <SkColorSpace.h>
#include <SkImageInfo.h>
+#include <SkRefCnt.h>
#include <android/data_space.h>
#include <mutex>
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index c24cabb287de..7291cab364e2 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -22,8 +22,11 @@
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <GrDirectContext.h>
+#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkImage.h>
+#include <SkImageInfo.h>
+#include <SkRefCnt.h>
#include <gui/TraceUtils.h>
#include <utils/GLUtils.h>
#include <utils/NdkUtils.h>
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 81057a24c29c..00ee99648889 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -17,6 +17,9 @@
#pragma once
#include <hwui/Bitmap.h>
+#include <SkRefCnt.h>
+
+class SkBitmap;
namespace android::uirenderer {
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 4cce87ad1a2f..79953aa6adc9 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -26,6 +26,18 @@
#include "pipeline/skia/LayerDrawable.h"
#include "renderthread/EglManager.h"
#include "renderthread/VulkanManager.h"
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColorSpace.h>
+#include <SkImage.h>
+#include <SkImageInfo.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkSamplingOptions.h>
+#include <SkSurface.h>
#include "utils/Color.h"
#include "utils/MathUtils.h"
#include "utils/NdkUtils.h"
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index d0d748ff5c16..aa6e43c3bc27 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -20,7 +20,11 @@
#include "Rect.h"
#include "renderthread/RenderThread.h"
-#include <SkBitmap.h>
+#include <SkRefCnt.h>
+
+class SkBitmap;
+class SkImage;
+struct SkRect;
namespace android {
class Bitmap;
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index a285462eef74..f5ebfd5d9e23 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -29,10 +29,14 @@
#include "SkDrawShadowInfo.h"
#include "SkImage.h"
#include "SkImageFilter.h"
+#include "SkImageInfo.h"
#include "SkLatticeIter.h"
#include "SkMath.h"
+#include "SkPaint.h"
#include "SkPicture.h"
+#include "SkRRect.h"
#include "SkRSXform.h"
+#include "SkRect.h"
#include "SkRegion.h"
#include "SkTextBlob.h"
#include "SkVertices.h"
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 212b4e72dcb2..35bec9335d7c 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -34,6 +34,8 @@
#include <SkRuntimeEffect.h>
#include <vector>
+class SkRRect;
+
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index da0476259b97..bdc48e91f6cb 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -16,7 +16,6 @@
#pragma once
-#include <SkCamera.h>
#include <SkMatrix.h>
#include <utils/LinearAllocator.h>
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 53c6db0cdf3a..023d6bf0b673 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -27,6 +27,7 @@
#include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h>
+#include <SkBitmap.h>
#include <SkCanvasPriv.h>
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
@@ -36,8 +37,13 @@
#include <SkGraphics.h>
#include <SkImage.h>
#include <SkImagePriv.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
#include <SkPicture.h>
#include <SkRSXform.h>
+#include <SkRRect.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
#include <SkShader.h>
#include <SkTemplates.h>
#include <SkTextBlob.h>
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 715007cdcd3b..c6313f6c3a88 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -33,6 +33,8 @@
#include <cassert>
#include <optional>
+class SkRRect;
+
namespace android {
// Holds an SkCanvas reference plus additional native data.
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 983c7766273a..536ff781badc 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -21,9 +21,10 @@
#include <utils/Log.h>
#include "PathParser.h"
-#include "SkColorFilter.h"
+#include "SkImage.h"
#include "SkImageInfo.h"
-#include "SkShader.h"
+#include "SkSamplingOptions.h"
+#include "SkScalar.h"
#include "hwui/Paint.h"
#ifdef __ANDROID__
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 30bb04ae8361..c92654c479c1 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,6 +31,7 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
+#include <SkRefCnt.h>
#include <SkShader.h>
#include <SkSurface.h>
diff --git a/libs/hwui/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp
index bc6bc456ba5a..c442a7b1d17c 100644
--- a/libs/hwui/apex/android_bitmap.cpp
+++ b/libs/hwui/apex/android_bitmap.cpp
@@ -24,6 +24,11 @@
#include <GraphicsJNI.h>
#include <hwui/Bitmap.h>
+#include <SkBitmap.h>
+#include <SkColorSpace.h>
+#include <SkImageInfo.h>
+#include <SkRefCnt.h>
+#include <SkStream.h>
#include <utils/Color.h>
using namespace android;
diff --git a/libs/hwui/apex/android_canvas.cpp b/libs/hwui/apex/android_canvas.cpp
index 2a939efed9bb..905b123076a2 100644
--- a/libs/hwui/apex/android_canvas.cpp
+++ b/libs/hwui/apex/android_canvas.cpp
@@ -23,7 +23,9 @@
#include <utils/Color.h>
#include <SkBitmap.h>
+#include <SkColorSpace.h>
#include <SkSurface.h>
+#include <SkRefCnt.h>
using namespace android;
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index fdc97a4fd8ba..2dcbca8273e7 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -17,13 +17,19 @@
#pragma once
#include <SkAndroidFrameworkUtils.h>
+#include <SkBlendMode.h>
#include <SkCanvas.h>
-#include <SkPath.h>
-#include <SkRegion.h>
-#include <SkVertices.h>
+#include <SkClipOp.h>
#include <SkImage.h>
+#include <SkPaint.h>
+#include <SkPath.h>
#include <SkPicture.h>
+#include <SkRRect.h>
+#include <SkRect.h>
+#include <SkRegion.h>
#include <SkRuntimeEffect.h>
+#include <SkSamplingOptions.h>
+#include <SkVertices.h>
#include <log/log.h>
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 67f47580a70f..feafc2372442 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -35,9 +35,15 @@
#endif
#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkEncodedImageFormat.h>
+#include <SkHighContrastFilter.h>
+#include <SkImageEncoder.h>
#include <SkImagePriv.h>
+#include <SkPixmap.h>
+#include <SkRect.h>
+#include <SkStream.h>
#include <SkWebpEncoder.h>
-#include <SkHighContrastFilter.h>
#include <limits>
namespace android {
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 94a047c06ced..133f1fe0a1e7 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -19,9 +19,9 @@
#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkImage.h>
-#include <SkImage.h>
#include <SkImageInfo.h>
#include <SkPixelRef.h>
+#include <SkRefCnt.h>
#include <cutils/compiler.h>
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
#include <android/hardware_buffer.h>
diff --git a/libs/hwui/hwui/BlurDrawLooper.cpp b/libs/hwui/hwui/BlurDrawLooper.cpp
index 270d24af99fd..d4b0198d015d 100644
--- a/libs/hwui/hwui/BlurDrawLooper.cpp
+++ b/libs/hwui/hwui/BlurDrawLooper.cpp
@@ -15,6 +15,7 @@
*/
#include "BlurDrawLooper.h"
+#include <SkColorSpace.h>
#include <SkMaskFilter.h>
namespace android {
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index b046f45d9c57..cd8af3d933b1 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -26,6 +26,7 @@
#include "hwui/PaintFilter.h"
#include <SkFontMetrics.h>
+#include <SkRRect.h>
namespace android {
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 82777646f3a2..7378351ef771 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -31,6 +31,7 @@
class SkAnimatedImage;
class SkCanvasState;
+class SkRRect;
class SkRuntimeShaderBuilder;
class SkVertices;
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index cef2233fc371..b6d73b39d8d0 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -17,9 +17,11 @@
#include <SkAndroidCodec.h>
#include <SkCodec.h>
+#include <SkColorSpace.h>
#include <SkImageInfo.h>
#include <SkPngChunkReader.h>
#include <SkRect.h>
+#include <SkRefCnt.h>
#include <SkSize.h>
#include <cutils/compiler.h>
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 2db3ace1cd43..34cb4aef70d9 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -16,10 +16,13 @@
#include "MinikinSkia.h"
-#include <SkFontDescriptor.h>
#include <SkFont.h>
+#include <SkFontDescriptor.h>
#include <SkFontMetrics.h>
#include <SkFontMgr.h>
+#include <SkRect.h>
+#include <SkScalar.h>
+#include <SkStream.h>
#include <SkTypeface.h>
#include <log/log.h>
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index c40b858268be..373e893b9a25 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -21,8 +21,11 @@
#include <SkAndroidCodec.h>
#include <SkAnimatedImage.h>
#include <SkColorFilter.h>
+#include <SkEncodedImageFormat.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
#include <hwui/AnimatedImageDrawable.h>
#include <hwui/ImageDecoder.h>
#include <hwui/Canvas.h>
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 5db0783cf83e..94cea65897cf 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -2,17 +2,25 @@
#define LOG_TAG "Bitmap"
#include "Bitmap.h"
+#include "GraphicsJNI.h"
#include "SkBitmap.h"
+#include "SkBlendMode.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkColorSpace.h"
-#include "SkPixelRef.h"
+#include "SkData.h"
#include "SkImageEncoder.h"
#include "SkImageInfo.h"
-#include "GraphicsJNI.h"
+#include "SkPaint.h"
+#include "SkPixelRef.h"
+#include "SkPixmap.h"
+#include "SkPoint.h"
+#include "SkRefCnt.h"
#include "SkStream.h"
+#include "SkTypes.h"
#include "SkWebpEncoder.h"
+
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include <hwui/Paint.h>
diff --git a/libs/hwui/jni/Bitmap.h b/libs/hwui/jni/Bitmap.h
index 73eca3aa8ef8..21a93f066d9b 100644
--- a/libs/hwui/jni/Bitmap.h
+++ b/libs/hwui/jni/Bitmap.h
@@ -19,7 +19,6 @@
#include <jni.h>
#include <android/bitmap.h>
-class SkBitmap;
struct SkImageInfo;
namespace android {
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 4e9daa4b0c16..320d3322904f 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -8,9 +8,19 @@
#include "MimeType.h"
#include "NinePatchPeeker.h"
#include "SkAndroidCodec.h"
+#include "SkBitmap.h"
+#include "SkBlendMode.h"
#include "SkCanvas.h"
+#include "SkColorSpace.h"
+#include "SkEncodedImageFormat.h"
+#include "SkImageInfo.h"
#include "SkMath.h"
+#include "SkPaint.h"
#include "SkPixelRef.h"
+#include "SkRect.h"
+#include "SkRefCnt.h"
+#include "SkSamplingOptions.h"
+#include "SkSize.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkUtils.h"
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index 1c20415dcc8f..eb56ae310231 100644
--- a/libs/hwui/jni/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -25,6 +25,7 @@
#include "BitmapRegionDecoder.h"
#include "SkBitmap.h"
#include "SkCodec.h"
+#include "SkColorSpace.h"
#include "SkData.h"
#include "SkStream.h"
diff --git a/libs/hwui/jni/ByteBufferStreamAdaptor.cpp b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp
index b10540cb3fbd..97dbc9ac171f 100644
--- a/libs/hwui/jni/ByteBufferStreamAdaptor.cpp
+++ b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp
@@ -2,6 +2,7 @@
#include "GraphicsJNI.h"
#include "Utils.h"
+#include <SkData.h>
#include <SkStream.h>
using namespace android;
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index ce5ac382aeff..acc1b0424030 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -24,6 +24,7 @@
#include "SkData.h"
#include "SkFontMgr.h"
#include "SkRefCnt.h"
+#include "SkStream.h"
#include "SkTypeface.h"
#include "Utils.h"
#include "fonts/Font.h"
diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index fef51b8d2f79..ae6ac4ce4ecc 100644
--- a/libs/hwui/jni/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
@@ -7,9 +7,11 @@
#include "Movie.h"
+#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkStream.h"
+#include "SkTypes.h"
#include "gif_lib.h"
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index 33669ac0a34e..6a3bc8fe1152 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -8,10 +8,18 @@
#include <nativehelper/JNIHelp.h>
#include "GraphicsJNI.h"
+#include "include/private/SkTemplates.h" // SkTAddOffset
+#include "SkBitmap.h"
#include "SkCanvas.h"
+#include "SkColorSpace.h"
#include "SkFontMetrics.h"
+#include "SkImageInfo.h"
#include "SkMath.h"
+#include "SkPixelRef.h"
+#include "SkPoint.h"
+#include "SkRect.h"
#include "SkRegion.h"
+#include "SkTypes.h"
#include <cutils/ashmem.h>
#include <hwui/Canvas.h>
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index f7b8c014be6e..bad710dec274 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -29,8 +29,12 @@
#include <FrontBufferedStream.h>
#include <SkAndroidCodec.h>
-#include <SkEncodedImageFormat.h>
+#include <SkBitmap.h>
+#include <SkColorSpace.h>
+#include <SkImageInfo.h>
+#include <SkRect.h>
#include <SkStream.h>
+#include <SkString.h>
#include <androidfw/Asset.h>
#include <fcntl.h>
diff --git a/libs/hwui/jni/Movie.h b/libs/hwui/jni/Movie.h
index 736890d5215e..02113dd58ec8 100644
--- a/libs/hwui/jni/Movie.h
+++ b/libs/hwui/jni/Movie.h
@@ -13,6 +13,7 @@
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkRefCnt.h"
+#include "SkTypes.h"
class SkStreamRewindable;
diff --git a/libs/hwui/jni/MovieImpl.cpp b/libs/hwui/jni/MovieImpl.cpp
index ae9e04e617b0..abb75fa99c94 100644
--- a/libs/hwui/jni/MovieImpl.cpp
+++ b/libs/hwui/jni/MovieImpl.cpp
@@ -5,11 +5,12 @@
* found in the LICENSE file.
*/
#include "Movie.h"
-#include "SkCanvas.h"
-#include "SkPaint.h"
+#include "SkBitmap.h"
+#include "SkStream.h"
+#include "SkTypes.h"
// We should never see this in normal operation since our time values are
-// 0-based. So we use it as a sentinal.
+// 0-based. So we use it as a sentinel.
#define UNINITIALIZED_MSEC ((SkMSec)-1)
Movie::Movie()
@@ -81,8 +82,6 @@ const SkBitmap& Movie::bitmap()
////////////////////////////////////////////////////////////////////
-#include "SkStream.h"
-
Movie* Movie::DecodeMemory(const void* data, size_t length) {
SkMemoryStream stream(data, length, false);
return Movie::DecodeStream(&stream);
diff --git a/libs/hwui/jni/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index 08fc80fbdafd..d50a8a22b5cb 100644
--- a/libs/hwui/jni/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -24,8 +24,10 @@
#include <hwui/Paint.h>
#include <utils/Log.h>
+#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkLatticeIter.h"
+#include "SkRect.h"
#include "SkRegion.h"
#include "GraphicsJNI.h"
#include "NinePatchPeeker.h"
diff --git a/libs/hwui/jni/NinePatchPeeker.cpp b/libs/hwui/jni/NinePatchPeeker.cpp
index 9171fc687276..d85ede5dc6d2 100644
--- a/libs/hwui/jni/NinePatchPeeker.cpp
+++ b/libs/hwui/jni/NinePatchPeeker.cpp
@@ -16,7 +16,7 @@
#include "NinePatchPeeker.h"
-#include <SkBitmap.h>
+#include <SkScalar.h>
#include <cutils/compiler.h>
using namespace android;
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index f76863255153..0aa14655725c 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -26,6 +26,7 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include "SkColorFilter.h"
+#include "SkColorSpace.h"
#include "SkFont.h"
#include "SkFontMetrics.h"
#include "SkFontTypes.h"
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0bbd8a8cf97c..fa8e2e79c831 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -2,11 +2,21 @@
#define LOG_TAG "ShaderJNI"
#include "GraphicsJNI.h"
+#include "SkBitmap.h"
+#include "SkBlendMode.h"
+#include "SkColor.h"
#include "SkColorFilter.h"
#include "SkGradientShader.h"
+#include "SkImage.h"
#include "SkImagePriv.h"
+#include "SkMatrix.h"
+#include "SkPoint.h"
+#include "SkRefCnt.h"
+#include "SkSamplingOptions.h"
+#include "SkScalar.h"
#include "SkShader.h"
-#include "SkBlendMode.h"
+#include "SkString.h"
+#include "SkTileMode.h"
#include "include/effects/SkRuntimeEffect.h"
#include <vector>
@@ -16,7 +26,7 @@ using namespace android::uirenderer;
/**
* By default Skia gradients will interpolate their colors in unpremul space
* and then premultiply each of the results. We must set this flag to preserve
- * backwards compatiblity by premultiplying the colors of the gradient first,
+ * backwards compatibility by premultiplying the colors of the gradient first,
* and then interpolating between them.
*/
static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
diff --git a/libs/hwui/jni/Utils.h b/libs/hwui/jni/Utils.h
index 6cdf44d85a5a..f6e3a0eeaa0e 100644
--- a/libs/hwui/jni/Utils.h
+++ b/libs/hwui/jni/Utils.h
@@ -17,8 +17,11 @@
#ifndef _ANDROID_GRAPHICS_UTILS_H_
#define _ANDROID_GRAPHICS_UTILS_H_
+#include "SkRefCnt.h"
#include "SkStream.h"
+class SkData;
+
#include <jni.h>
#include <androidfw/Asset.h>
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 77f42ae70268..87eda7e9f96f 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -1,5 +1,7 @@
#include "CreateJavaOutputStreamAdaptor.h"
#include "SkJPEGWriteUtility.h"
+#include "SkStream.h"
+#include "SkTypes.h"
#include "YuvToJpegEncoder.h"
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index 7e7b935df276..a69726b17e9d 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
@@ -1,13 +1,13 @@
#ifndef _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
#define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
-#include "SkTypes.h"
-#include "SkStream.h"
extern "C" {
#include "jpeglib.h"
#include "jerror.h"
}
+class SkWStream;
+
class YuvToJpegEncoder {
public:
/** Create an encoder based on the YUV format.
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0ef80ee10708..61bb66557adc 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -32,10 +32,22 @@
#include "FontUtils.h"
#include "Bitmap.h"
+#include "SkBitmap.h"
+#include "SkBlendMode.h"
+#include "SkClipOp.h"
+#include "SkColor.h"
+#include "SkColorSpace.h"
#include "SkGraphics.h"
+#include "SkImageInfo.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkRefCnt.h"
#include "SkRegion.h"
-#include "SkVertices.h"
#include "SkRRect.h"
+#include "SkScalar.h"
+#include "SkVertices.h"
namespace minikin {
class MeasuredText;
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index c48448dffdd2..55b1f23d294a 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -23,8 +23,16 @@
#include <Picture.h>
#include <Properties.h>
#include <RootRenderNode.h>
+#include <SkBitmap.h>
+#include <SkColorSpace.h>
+#include <SkData.h>
+#include <SkImage.h>
#include <SkImagePriv.h>
+#include <SkPicture.h>
+#include <SkPixmap.h>
#include <SkSerialProcs.h>
+#include <SkStream.h>
+#include <SkTypeface.h>
#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <inttypes.h>
@@ -451,7 +459,7 @@ struct PictureCaptureState {
};
// TODO: This & Multi-SKP & Single-SKP should all be de-duped into
-// a single "make a SkPicture serailizable-safe" utility somewhere
+// a single "make a SkPicture serializable-safe" utility somewhere
class PictureWrapper : public Picture {
public:
PictureWrapper(sk_sp<SkPicture>&& src, const std::shared_ptr<PictureCaptureState>& state)
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 09be630dc741..2c421f8727a8 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -22,7 +22,10 @@
#include "SkFont.h"
#include "SkFontMetrics.h"
#include "SkFontMgr.h"
+#include "SkRect.h"
#include "SkRefCnt.h"
+#include "SkScalar.h"
+#include "SkStream.h"
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <nativehelper/ScopedUtfChars.h>
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 3f89c0712407..6a052dbb7cea 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -19,6 +19,8 @@
#include "RenderNode.h"
#include "SkiaDisplayList.h"
+class SkRRect;
+
namespace android {
namespace uirenderer {
namespace skiapipeline {
diff --git a/libs/hwui/pipeline/skia/HolePunch.h b/libs/hwui/pipeline/skia/HolePunch.h
index 92c6f7721a08..d0e1ca35049a 100644
--- a/libs/hwui/pipeline/skia/HolePunch.h
+++ b/libs/hwui/pipeline/skia/HolePunch.h
@@ -17,7 +17,6 @@
#pragma once
#include <string>
-#include "SkRRect.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 507d3dcdcde9..3bf2b2e63a47 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -15,7 +15,11 @@
*/
#include "RenderNodeDrawable.h"
+#include <SkPaint.h>
#include <SkPaintFilterCanvas.h>
+#include <SkPoint.h>
+#include <SkRRect.h>
+#include <SkRect.h>
#include <gui/TraceUtils.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 7cfccb56382c..11977bd54c2c 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -19,8 +19,15 @@
#include "SkiaDisplayList.h"
#include "LightingInfo.h"
+#include <SkColor.h>
+#include <SkMatrix.h>
+#include <SkPath.h>
#include <SkPathOps.h>
+#include <SkPoint3.h>
+#include <SkRect.h>
+#include <SkScalar.h>
#include <SkShadowUtils.h>
+#include <include/private/SkShadowFlags.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 90c4440c8339..a55de95035a7 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -16,6 +16,7 @@
#include "ShaderCache.h"
#include <GrDirectContext.h>
+#include <SkData.h>
#include <gui/TraceUtils.h>
#include <log/log.h>
#include <openssl/sha.h>
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 3e0fd5164011..bc35fa5f9987 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -17,12 +17,15 @@
#pragma once
#include <GrContextOptions.h>
+#include <SkRefCnt.h>
#include <cutils/compiler.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
+class SkData;
+
namespace android {
class BlobCache;
@@ -45,7 +48,7 @@ public:
* and puts the ShaderCache into an initialized state, such that it is
* able to insert and retrieve entries from the cache. If identity is
* non-null and validation fails, the cache is initialized but contains
- * no data. If size is less than zero, the cache is initilaized but
+ * no data. If size is less than zero, the cache is initialized but
* contains no data.
*
* This should be called when HWUI pipeline is initialized. When not in
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index bc386feb2d6f..c546adaaf779 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -16,15 +16,25 @@
#include "SkiaPipeline.h"
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkColorSpace.h>
+#include <SkData.h>
+#include <SkImage.h>
#include <SkImageEncoder.h>
#include <SkImageInfo.h>
#include <SkImagePriv.h>
+#include <SkMatrix.h>
#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
#include <SkSerialProcs.h>
+#include <SkStream.h>
+#include <SkString.h>
#include <SkTypeface.h>
#include <android-base/properties.h>
#include <unistd.h>
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index bc8a5659dd83..7887d1ae2117 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -16,14 +16,16 @@
#pragma once
-#include <SkSurface.h>
+#include <SkColorSpace.h>
#include <SkDocument.h>
#include <SkMultiPictureDocument.h>
+#include <SkSurface.h>
#include "Lighting.h"
#include "hwui/AnimatedImageDrawable.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/IRenderPipeline.h"
+class SkFILEWStream;
class SkPictureRecorder;
struct SkSharingSerialContext;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 9c51e628e04a..5c6117d86415 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -16,7 +16,20 @@
#include "SkiaRecordingCanvas.h"
#include "hwui/Paint.h"
+#include <include/private/SkTemplates.h> // SkAutoSTMalloc
+#include <SkBlendMode.h>
+#include <SkData.h>
+#include <SkDrawable.h>
+#include <SkImage.h>
#include <SkImagePriv.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPoint.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkRRect.h>
+#include <SkSamplingOptions.h>
+#include <SkTypes.h>
#include "CanvasTransform.h"
#ifdef __ANDROID__ // Layoutlib does not support Layers
#include "Layer.h"
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 1445a27e4248..89e3a2c24e1e 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -22,6 +22,11 @@
#include "SkiaDisplayList.h"
#include "pipeline/skia/AnimatedDrawables.h"
+class SkBitmap;
+class SkMatrix;
+class SkPaint;
+class SkRRect;
+
namespace android {
namespace uirenderer {
namespace skiapipeline {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index ada6af67d4a0..d2bdae535f3c 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -22,6 +22,11 @@
#include "renderstate/RenderState.h"
+#include "SkRefCnt.h"
+
+class SkBitmap;
+struct SkRect;
+
namespace android {
namespace uirenderer {
namespace skiapipeline {
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
index 41e36874b862..33160d05e2d0 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.cpp
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -19,6 +19,10 @@
#include "HolePunch.h"
#include "SkData.h"
#include "SkDrawable.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+#include "SkRRect.h"
using namespace android::uirenderer::skiapipeline;
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.h b/libs/hwui/pipeline/skia/TransformCanvas.h
index 685b71d017e9..15f0c1abc55a 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.h
+++ b/libs/hwui/pipeline/skia/TransformCanvas.h
@@ -19,6 +19,13 @@
#include "SkPaintFilterCanvas.h"
#include <effects/StretchEffect.h>
+class SkData;
+class SkDrawable;
+class SkMatrix;
+class SkPaint;
+enum class SkBlendMode;
+struct SkRect;
+
class TransformCanvas : public SkPaintFilterCanvas {
public:
TransformCanvas(SkCanvas* target, SkBlendMode blendmode) :
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index fc6b28d2e1ad..b8f8c9267ad8 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -18,6 +18,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <SkColorSpace.h>
#include <SkImageInfo.h>
#include <SkRect.h>
#include <cutils/compiler.h>
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ef58bc553c23..35e370f52fda 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -24,6 +24,7 @@
#include "hwui/Bitmap.h"
#include "ColorMode.h"
+#include <SkColorSpace.h>
#include <SkRect.h>
#include <utils/RefBase.h>
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a44b498c81c1..b2ba15cbe526 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -29,6 +29,10 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
+#include <SkBitmap.h>
+#include <SkImage.h>
+#include <SkPicture.h>
+
#include <pthread.h>
namespace android {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index ee9efd46e307..bbfeeac19d94 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -17,7 +17,7 @@
#ifndef RENDERPROXY_H_
#define RENDERPROXY_H_
-#include <SkBitmap.h>
+#include <SkRefCnt.h>
#include <android/native_window.h>
#include <cutils/compiler.h>
#include <android/surface_control.h>
@@ -30,6 +30,10 @@
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
+class SkBitmap;
+class SkPicture;
+class SkImage;
+
namespace android {
class GraphicBuffer;
class Surface;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 01b956cb3dd5..3ff4081726f3 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -266,7 +266,7 @@ void RenderThread::requireGlContext() {
}
mEglManager->initialize();
- sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+ sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index b8c2bdf112f8..81bcb4e609df 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -51,6 +51,9 @@ typedef void(VKAPI_PTR* PFN_vkFrameBoundaryANDROID)(VkDevice device, VkSemaphore
#include "VulkanSurface.h"
#include "private/hwui/DrawVkInfo.h"
+#include <SkColorSpace.h>
+#include <SkRefCnt.h>
+
class GrVkExtensions;
namespace android {
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index beb71b727f51..26486669e712 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -20,6 +20,7 @@
#include <system/window.h>
#include <vulkan/vulkan.h>
+#include <SkColorSpace.h>
#include <SkRefCnt.h>
#include <SkSize.h>
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 491af4336f97..a4890ede8faa 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -26,7 +26,13 @@
#include <renderthread/VulkanManager.h>
#include <utils/Unicode.h>
+#include "SkCanvas.h"
#include "SkColorData.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkPixmap.h"
+#include "SkRect.h"
+#include "SkSurface.h"
#include "SkUnPreMultiply.h"
namespace android {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 5092675a8104..75865c751d52 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -27,10 +27,20 @@
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
+#include <SkBitmap.h>
+#include <SkColor.h>
+#include <SkImageInfo.h>
+#include <SkRefCnt.h>
+
#include <gtest/gtest.h>
#include <memory>
#include <unordered_map>
+class SkCanvas;
+class SkMatrix;
+class SkPath;
+struct SkRect;
+
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 03aeb55f129b..a07cdf720b50 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -14,7 +14,17 @@
* limitations under the License.
*/
-#include <SkImagePriv.h>
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkImage.h>
+#include <SkImageInfo.h>
+#include <SkPaint.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkSamplingOptions.h>
+#include <SkShader.h>
+#include <SkTileMode.h>
#include "hwui/Paint.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
diff --git a/libs/hwui/tests/common/scenes/HwBitmap565.cpp b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
index cbdb756b8fa7..de0ef6d595f8 100644
--- a/libs/hwui/tests/common/scenes/HwBitmap565.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
@@ -18,6 +18,12 @@
#include "tests/common/BitmapAllocationTestUtils.h"
#include "utils/Color.h"
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkRefCnt.h>
+
class HwBitmap565;
static TestScene::Registrar _HwBitmap565(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 564354f04674..0d5ca6df9ff3 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -17,6 +17,7 @@
#include "TestSceneBase.h"
#include "utils/Color.h"
+#include <SkColorSpace.h>
#include <SkGradientShader.h>
#include <SkImagePriv.h>
#include <ui/PixelFormat.h>
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index d031923a112b..4a5d9468cd88 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -17,7 +17,16 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
#include "hwui/Paint.h"
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
#include <SkFont.h>
+#include <SkFontTypes.h>
+#include <SkPaint.h>
+#include <SkPoint.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkScalar.h>
#include <cstdio>
class ListViewAnimation;
@@ -48,7 +57,7 @@ class ListViewAnimation : public TestListViewSceneBase {
128 * 3;
paint.setColor(bgDark ? Color::White : Color::Grey_700);
- SkFont font;
+ SkFont font;
font.setSize(size / 2);
char charToShow = 'A' + (rand() % 26);
const SkPoint pos = {SkIntToScalar(size / 2),
diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
index edadf78db051..070a339a86a1 100644
--- a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
@@ -19,6 +19,10 @@
#include "utils/Color.h"
#include "hwui/Paint.h"
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkFont.h>
+
class MagnifierAnimation;
static TestScene::Registrar _Magnifier(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
index 716d3979bdcb..3caaf8236d8a 100644
--- a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
+++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
@@ -16,6 +16,12 @@
#include "TestSceneBase.h"
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+
class ReadbackFromHardware;
static TestScene::Registrar _SaveLayer(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
index 1c2507867f6e..27948f8b4b43 100644
--- a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
@@ -17,6 +17,11 @@
#include "TestSceneBase.h"
#include "utils/Color.h"
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkColor.h>
+#include <SkRefCnt.h>
+
class RecentsAnimation;
static TestScene::Registrar _Recents(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
index e677549b7894..59230a754f4e 100644
--- a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
@@ -14,7 +14,15 @@
* limitations under the License.
*/
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
#include <SkFont.h>
+#include <SkFontTypes.h>
+#include <SkPaint.h>
+#include <SkPoint.h>
+#include <SkRefCnt.h>
+#include <SkRRect.h>
#include <cstdio>
#include "TestSceneBase.h"
#include "hwui/Paint.h"
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index c6219c485b85..aff8ca1e26c7 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -14,7 +14,12 @@
* limitations under the License.
*/
+#include "SkBitmap.h"
#include "SkBlendMode.h"
+#include "SkColorFilter.h"
+#include "SkFont.h"
+#include "SkImageInfo.h"
+#include "SkRefCnt.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
#include "hwui/Paint.h"
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index 2cf3456694b0..d2b1ef91a898 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -23,9 +23,17 @@
#include <tests/common/CallCountingCanvas.h>
-#include "SkPictureRecorder.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
#include "SkColor.h"
+#include "SkImageInfo.h"
#include "SkLatticeIter.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPictureRecorder.h"
+#include "SkRRect.h"
+#include "SkRect.h"
+#include "SkRegion.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include <SkNoDrawCanvas.h>
diff --git a/libs/hwui/tests/unit/EglManagerTests.cpp b/libs/hwui/tests/unit/EglManagerTests.cpp
index 7f2e1589ae6c..ec9ab90fa46b 100644
--- a/libs/hwui/tests/unit/EglManagerTests.cpp
+++ b/libs/hwui/tests/unit/EglManagerTests.cpp
@@ -20,6 +20,8 @@
#include "renderthread/RenderEffectCapabilityQuery.h"
#include "tests/common/TestContext.h"
+#include <SkColorSpace.h>
+
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 2a74afc5bb7a..96a0c6114682 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -19,6 +19,8 @@
#include <SkCanvas.h>
#include <gtest/gtest.h>
+class SkRRect;
+
namespace {
class TestCanvasBase : public SkCanvas {
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 974d85a453db..576e9466d322 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -25,6 +25,8 @@
#include <cstdint>
#include "FileBlobCache.h"
#include "pipeline/skia/ShaderCache.h"
+#include <SkData.h>
+#include <SkRefCnt.h>
using namespace android::uirenderer::skiapipeline;
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index dc1b2e668dd0..c1ddbd36bcfd 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -16,9 +16,14 @@
#include "tests/common/TestUtils.h"
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkColor.h>
#include <SkColorMatrixFilter.h>
#include <SkColorSpace.h>
-#include <SkImagePriv.h>
+#include <SkImageInfo.h>
+#include <SkPaint.h>
+#include <SkPath.h>
#include <SkPathOps.h>
#include <SkShader.h>
#include <gtest/gtest.h>
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index dae3c9435712..50d9f5683a8b 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -18,6 +18,7 @@
#include <hwui/Paint.h>
#include <SkCanvasStateUtils.h>
+#include <SkColorSpace.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
#include <gtest/gtest.h>
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 15ecf5831f3a..ced667eb76e5 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -17,6 +17,7 @@
#include <VectorDrawable.h>
#include <gtest/gtest.h>
+#include <SkCanvas.h>
#include <SkClipStack.h>
#include <SkSurface_Base.h>
#include <string.h>
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index ab23448ab93f..9295a938f397 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -21,8 +21,11 @@
#include <sys/stat.h>
#include <utils/Log.h>
+#include "SkData.h"
#include "SkFontMgr.h"
+#include "SkRefCnt.h"
#include "SkStream.h"
+#include "SkTypeface.h"
#include "hwui/MinikinSkia.h"
#include "hwui/Typeface.h"
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 6d4c57413f00..c1c21bd7dfbf 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -21,6 +21,12 @@
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkPath.h>
+#include <SkRefCnt.h>
+#include <SkShader.h>
+
#include <functional>
namespace android {
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 45da008c3e8e..956101e7a2a4 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -24,12 +24,6 @@
#include <log/log.h>
-#include <SkBitmap.h>
-#include <SkBlendMode.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkPaint.h>
-
namespace {
// Time to spend fading out the pointer completely.
const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 2b809eab4ae4..a5ca49847bb6 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -249,8 +249,7 @@ void SpriteController::doUpdateSprites() {
// Pass cursor metadata in the sprite surface so that when Android is running as a
// client OS (e.g. ARC++) the host OS can get the requested cursor metadata and
// update mouse cursor in the host OS.
- t.setMetadata(
- update.state.surfaceControl, METADATA_MOUSE_CURSOR, p);
+ t.setMetadata(update.state.surfaceControl, gui::METADATA_MOUSE_CURSOR, p);
}
int32_t surfaceLayer = mOverlayLayer + update.state.layer;
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index f7c685ff8ba6..4ac66c4ffb6a 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -23,12 +23,6 @@
#include <log/log.h>
-#include <SkBitmap.h>
-#include <SkBlendMode.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkPaint.h>
-
namespace {
// Time to spend fading out the spot completely.
const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java
index 26f73f784879..b12a8a0b6702 100644
--- a/location/java/android/location/Criteria.java
+++ b/location/java/android/location/Criteria.java
@@ -27,11 +27,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * A class indicating the application criteria for selecting a
- * location provider. Providers may be ordered according to accuracy,
- * power usage, ability to report altitude, speed, bearing, and monetary
- * cost.
+ * A class indicating the application criteria for selecting a location provider. Providers may be
+ * ordered according to accuracy, power usage, ability to report altitude, speed, bearing, and
+ * monetary cost.
+ *
+ * @deprecated Criteria based APIs are deprecated because they cannot fully capture the complexity
+ * of location providers, and encourage bad development practices. Prefer to explicit
+ * select the location provider of interest ({@link LocationManager#FUSED_PROVIDER},
+ * {@link LocationManager#GPS_PROVIDER, etc}), rather than relying on Criteria.
*/
+@Deprecated
public class Criteria implements Parcelable {
/** @hide */
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 033056cb2a69..55ee3aaaaf77 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -95,6 +95,8 @@ public class Location implements Parcelable {
private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6;
private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7;
private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8;
+ private static final int HAS_MSL_ALTITUDE_MASK = 1 << 9;
+ private static final int HAS_MSL_ALTITUDE_ACCURACY_MASK = 1 << 10;
// Cached data to make bearing/distance computations more efficient for the case
// where distanceTo and bearingTo are called in sequence. Assume this typically happens
@@ -118,6 +120,8 @@ public class Location implements Parcelable {
private float mSpeedAccuracyMetersPerSecond;
private float mBearingDegrees;
private float mBearingAccuracyDegrees;
+ private double mMslAltitudeMeters;
+ private float mMslAltitudeAccuracyMeters;
private Bundle mExtras = null;
@@ -156,6 +160,8 @@ public class Location implements Parcelable {
mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
mBearingDegrees = location.mBearingDegrees;
mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+ mMslAltitudeMeters = location.mMslAltitudeMeters;
+ mMslAltitudeAccuracyMeters = location.mMslAltitudeAccuracyMeters;
mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
}
@@ -178,6 +184,8 @@ public class Location implements Parcelable {
mAltitudeAccuracyMeters = 0;
mSpeedAccuracyMetersPerSecond = 0;
mBearingAccuracyDegrees = 0;
+ mMslAltitudeMeters = 0;
+ mMslAltitudeAccuracyMeters = 0;
mExtras = null;
}
@@ -690,6 +698,75 @@ public class Location implements Parcelable {
}
/**
+ * Returns the Mean Sea Level altitude of this location in meters.
+ *
+ * <p>This is only valid if {@link #hasMslAltitude()} is true.
+ */
+ public @FloatRange double getMslAltitudeMeters() {
+ Preconditions.checkState(hasMslAltitude(),
+ "The Mean Sea Level altitude of this location is not set.");
+ return mMslAltitudeMeters;
+ }
+
+ /**
+ * Sets the Mean Sea Level altitude of this location in meters.
+ */
+ public void setMslAltitudeMeters(@FloatRange double mslAltitudeMeters) {
+ mMslAltitudeMeters = mslAltitudeMeters;
+ mFieldsMask |= HAS_MSL_ALTITUDE_MASK;
+ }
+
+ /**
+ * Returns true if this location has a Mean Sea Level altitude, false otherwise.
+ */
+ public boolean hasMslAltitude() {
+ return (mFieldsMask & HAS_MSL_ALTITUDE_MASK) != 0;
+ }
+
+ /**
+ * Removes the Mean Sea Level altitude from this location.
+ */
+ public void removeMslAltitude() {
+ mFieldsMask &= ~HAS_MSL_ALTITUDE_MASK;
+ }
+
+ /**
+ * Returns the estimated Mean Sea Level altitude accuracy in meters of this location at the 68th
+ * percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
+ * altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
+ *
+ * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
+ */
+ public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
+ Preconditions.checkState(hasMslAltitudeAccuracy(),
+ "The Mean Sea Level altitude accuracy of this location is not set.");
+ return mMslAltitudeAccuracyMeters;
+ }
+
+ /**
+ * Sets the Mean Sea Level altitude accuracy of this location in meters.
+ */
+ public void setMslAltitudeAccuracyMeters(
+ @FloatRange(from = 0.0) float mslAltitudeAccuracyMeters) {
+ mMslAltitudeAccuracyMeters = mslAltitudeAccuracyMeters;
+ mFieldsMask |= HAS_MSL_ALTITUDE_ACCURACY_MASK;
+ }
+
+ /**
+ * Returns true if this location has a Mean Sea Level altitude accuracy, false otherwise.
+ */
+ public boolean hasMslAltitudeAccuracy() {
+ return (mFieldsMask & HAS_MSL_ALTITUDE_ACCURACY_MASK) != 0;
+ }
+
+ /**
+ * Removes the Mean Sea Level altitude accuracy from this location.
+ */
+ public void removeMslAltitudeAccuracy() {
+ mFieldsMask &= ~HAS_MSL_ALTITUDE_ACCURACY_MASK;
+ }
+
+ /**
* Returns true if this is a mock location. If this location comes from the Android framework,
* this indicates that the location was provided by a test location provider, and thus may not
* be related to the actual location of the device.
@@ -839,6 +916,14 @@ public class Location implements Parcelable {
&& hasBearingAccuracy() == location.hasBearingAccuracy()
&& (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
mBearingAccuracyDegrees) == 0)
+ && hasMslAltitude() == location.hasMslAltitude()
+ && (!hasMslAltitude() || Double.compare(location.mMslAltitudeMeters,
+ mMslAltitudeMeters)
+ == 0)
+ && hasMslAltitudeAccuracy() == location.hasMslAltitudeAccuracy()
+ && (!hasMslAltitudeAccuracy() || Float.compare(
+ location.mMslAltitudeAccuracyMeters,
+ mMslAltitudeAccuracyMeters) == 0)
&& Objects.equals(mProvider, location.mProvider)
&& areExtrasEqual(mExtras, location.mExtras);
}
@@ -876,6 +961,12 @@ public class Location implements Parcelable {
s.append(" vAcc=").append(mAltitudeAccuracyMeters);
}
}
+ if (hasMslAltitude()) {
+ s.append(" mslAlt=").append(mMslAltitudeMeters);
+ if (hasMslAltitudeAccuracy()) {
+ s.append(" mslAltAcc=").append(mMslAltitudeAccuracyMeters);
+ }
+ }
if (hasSpeed()) {
s.append(" vel=").append(mSpeedMetersPerSecond);
if (hasSpeedAccuracy()) {
@@ -944,6 +1035,12 @@ public class Location implements Parcelable {
if (l.hasBearingAccuracy()) {
l.mBearingAccuracyDegrees = in.readFloat();
}
+ if (l.hasMslAltitude()) {
+ l.mMslAltitudeMeters = in.readDouble();
+ }
+ if (l.hasMslAltitudeAccuracy()) {
+ l.mMslAltitudeAccuracyMeters = in.readFloat();
+ }
l.mExtras = Bundle.setDefusable(in.readBundle(), true);
return l;
}
@@ -991,6 +1088,12 @@ public class Location implements Parcelable {
if (hasBearingAccuracy()) {
parcel.writeFloat(mBearingAccuracyDegrees);
}
+ if (hasMslAltitude()) {
+ parcel.writeDouble(mMslAltitudeMeters);
+ }
+ if (hasMslAltitudeAccuracy()) {
+ parcel.writeFloat(mMslAltitudeAccuracyMeters);
+ }
parcel.writeBundle(mExtras);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 371f5ed4f346..fd0c8948c321 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1807,7 +1807,10 @@ public class LocationManager {
* @return list of provider names
*
* @throws IllegalArgumentException if criteria is null
+ *
+ * @deprecated Criteria based APIs are deprecated, prefer to select a provider explicitly.
*/
+ @Deprecated
public @NonNull List<String> getProviders(@NonNull Criteria criteria, boolean enabledOnly) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
@@ -1839,7 +1842,10 @@ public class LocationManager {
* @return name of the provider that best matches the criteria, or null if none match
*
* @throws IllegalArgumentException if criteria is null
+ *
+ * @deprecated Criteria based APIs are deprecated, prefer to select a provider explicitly.
*/
+ @Deprecated
public @Nullable String getBestProvider(@NonNull Criteria criteria, boolean enabledOnly) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
@@ -2904,7 +2910,8 @@ public class LocationManager {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(allOf = {Manifest.permission.LOCATION_HARDWARE,
+ Manifest.permission.INTERACT_ACROSS_USERS})
public void addProviderRequestChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull ChangedListener listener) {
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 4385a807774f..803c33c69f7b 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -1,6 +1,9 @@
{
"presubmit": [
{
+ "name": "CtsMediaBetterTogetherTestCases"
+ },
+ {
"name": "CtsCameraTestCases",
"options" : [
{
diff --git a/media/aidl/android/media/audio/common/AudioPort.aidl b/media/aidl/android/media/audio/common/AudioPort.aidl
index 84675e3a00a6..d32b840ebfe8 100644
--- a/media/aidl/android/media/audio/common/AudioPort.aidl
+++ b/media/aidl/android/media/audio/common/AudioPort.aidl
@@ -23,8 +23,9 @@ import android.media.audio.common.AudioProfile;
import android.media.audio.common.ExtraAudioDescriptor;
/**
- * Audio port structure describes the capabilities of an audio port
- * as well as its current configuration.
+ * Audio port structure describes the capabilities of an audio port.
+ * This is a "blueprint" which contains all the possible configurations
+ * that are supported by the port.
*
* {@hide}
*/
diff --git a/media/aidl/android/media/audio/common/AudioPortExt.aidl b/media/aidl/android/media/audio/common/AudioPortExt.aidl
index c4681cbb182e..eadc0ab7c7c5 100644
--- a/media/aidl/android/media/audio/common/AudioPortExt.aidl
+++ b/media/aidl/android/media/audio/common/AudioPortExt.aidl
@@ -34,6 +34,9 @@ union AudioPortExt {
AudioPortDeviceExt device;
/** Information specific to mix ports. */
AudioPortMixExt mix;
- /** Audio session identifier. */
+ /**
+ * NOT USED. Framework audio session identifier.
+ * Use android.media.AudioPortExtSys.session on the system side.
+ */
int session;
}
diff --git a/media/aidl/android/media/audio/common/AudioPortMixExt.aidl b/media/aidl/android/media/audio/common/AudioPortMixExt.aidl
index f3613a4ae31f..eb117eca52bd 100644
--- a/media/aidl/android/media/audio/common/AudioPortMixExt.aidl
+++ b/media/aidl/android/media/audio/common/AudioPortMixExt.aidl
@@ -32,12 +32,12 @@ parcelable AudioPortMixExt {
AudioPortMixExtUseCase usecase;
/**
* Maximum number of input or output streams that can be simultaneously
- * opened for this port.
+ * opened for this port. '0' means 'unlimited'.
*/
int maxOpenStreamCount;
/**
* Maximum number of input or output streams that can be simultaneously
- * active for this port.
+ * active for this port. '0' means 'all opened streams'.
*/
int maxActiveStreamCount;
/** Mute duration while changing device, when used for output. */
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e7eda3ea4552..78fd944dc22b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1636,8 +1636,10 @@ public class AudioManager {
*
* @param on set <var>true</var> to turn on speakerphone;
* <var>false</var> to turn it off
+ * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
+ * {@link AudioManager#clearCommunicationDevice()} instead.
*/
- public void setSpeakerphoneOn(boolean on){
+ @Deprecated public void setSpeakerphoneOn(boolean on) {
final IAudioService service = getService();
try {
service.setSpeakerphoneOn(mICallBack, on);
@@ -1650,8 +1652,9 @@ public class AudioManager {
* Checks whether the speakerphone is on or off.
*
* @return true if speakerphone is on, false if it's off
+ * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
*/
- public boolean isSpeakerphoneOn() {
+ @Deprecated public boolean isSpeakerphoneOn() {
final IAudioService service = getService();
try {
return service.isSpeakerphoneOn();
@@ -2717,8 +2720,9 @@ public class AudioManager {
* connection is established.
* @see #stopBluetoothSco()
* @see #ACTION_SCO_AUDIO_STATE_UPDATED
+ * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
*/
- public void startBluetoothSco(){
+ @Deprecated public void startBluetoothSco() {
final IAudioService service = getService();
try {
service.startBluetoothSco(mICallBack,
@@ -2761,9 +2765,10 @@ public class AudioManager {
* bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
* connection or if connection fails.
* @see #startBluetoothSco()
+ * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
*/
// Also used for connections started with {@link #startBluetoothScoVirtualCall()}
- public void stopBluetoothSco(){
+ @Deprecated public void stopBluetoothSco() {
final IAudioService service = getService();
try {
service.stopBluetoothSco(mICallBack);
@@ -2795,8 +2800,9 @@ public class AudioManager {
*
* @return true if SCO is used for communications;
* false if otherwise
+ * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
*/
- public boolean isBluetoothScoOn() {
+ @Deprecated public boolean isBluetoothScoOn() {
final IAudioService service = getService();
try {
return service.isBluetoothScoOn();
@@ -4266,8 +4272,9 @@ public class AudioManager {
@NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
Objects.requireNonNull(afr);
Objects.requireNonNull(clientFakeId);
+ int status;
try {
- return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
+ status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
afr.getFocusGain(),
mICallBack,
mAudioFocusDispatcher,
@@ -4277,6 +4284,8 @@ public class AudioManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+
+ return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, status);
}
/**
@@ -4359,7 +4368,6 @@ public class AudioManager {
}
final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
- final BlockingFocusResultReceiver focusReceiver;
synchronized (mFocusRequestsLock) {
try {
// TODO status contains result and generation counter for ext policy
@@ -4375,10 +4383,21 @@ public class AudioManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
- // default path with no external focus policy
- return status;
- }
+ }
+
+ return handleExternalAudioPolicyWaitIfNeeded(clientId, status);
+ }
+
+ private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
+ @FocusRequestResult int results) {
+ if (results != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
+ // default path with no external focus policy
+ return results;
+ }
+
+ BlockingFocusResultReceiver focusReceiver;
+
+ synchronized (mFocusRequestsLock) {
if (mFocusRequestsAwaitingResult == null) {
mFocusRequestsAwaitingResult =
new HashMap<String, BlockingFocusResultReceiver>(1);
@@ -4386,10 +4405,13 @@ public class AudioManager {
focusReceiver = new BlockingFocusResultReceiver(clientId);
mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
}
+
focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
if (DEBUG && !focusReceiver.receivedResult()) {
- Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
+ Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
+ + " response from ext policy timed out, denying request");
}
+
synchronized (mFocusRequestsLock) {
mFocusRequestsAwaitingResult.remove(clientId);
}
@@ -6622,7 +6644,7 @@ public class AudioManager {
/**
* The message sent to apps when the contents of the device list changes if they provide
- * a {@link Handler} object to addOnAudioDeviceConnectionListener().
+ * a {@link Handler} object to {@link registerAudioDeviceCallback}.
*/
private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
private final static int MSG_DEVICES_DEVICES_ADDED = 1;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index ccc23b7069ba..c2be2efe19c6 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -758,7 +758,7 @@ import java.util.concurrent.locks.ReentrantLock;
<h4 id=KeyFrames><a name="KeyFrames"></a>Stream Boundary and Key Frames</h4>
<p>
It is important that the input data after {@link #start} or {@link #flush} starts at a suitable
- stream boundary: the first frame must a key frame. A <em>key frame</em> can be decoded
+ stream boundary: the first frame must be a key frame. A <em>key frame</em> can be decoded
completely on its own (for most codecs this means an I-frame), and no frames that are to be
displayed after a key frame refer to frames before the key frame.
<p>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3a0699ecb0ee..be9862bf1137 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -291,9 +291,10 @@ public final class MediaFormat {
/**
* A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte
* hexadecimal string that is used to associate metrics from multiple media codec instances
- * to the same playback or recording session.
+ * to the same playback or recording session. The value is created as
+ * {@link android.media.metrics.LogSessionId LogSessionId}. Sessions are created in
+ * {@link android.media.metrics.MediaMetricsManager MediaMetricsManager}.
* The associated value is a string.
- * @hide
*/
public static final String LOG_SESSION_ID = "log-session-id";
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index b8e7930e1dca..c63a5d8d36a2 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -430,8 +430,8 @@ final public class MediaMuxer {
* @throws IllegalStateException If this method is called after {@link #start}.
*/
public void setLocation(float latitude, float longitude) {
- int latitudex10000 = (int) (latitude * 10000 + 0.5);
- int longitudex10000 = (int) (longitude * 10000 + 0.5);
+ int latitudex10000 = Math.round(latitude * 10000);
+ int longitudex10000 = Math.round(longitude * 10000);
if (latitudex10000 > 900000 || latitudex10000 < -900000) {
String msg = "Latitude: " + latitude + " out of range.";
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 10772754bd6c..ee2e448bfdac 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -158,6 +158,9 @@ import java.util.concurrent.Executor;
* the user supplied callback method OnErrorListener.onError() will be
* invoked by the internal player engine and the object will be
* transfered to the <em>Error</em> state. </li>
+ * <li>You must keep a reference to a MediaPlayer instance to prevent it from being garbage
+ * collected. If a MediaPlayer instance is garbage collected, {@link #release} will be
+ * called, causing any ongoing playback to stop.
* <li>You must call {@link #release()} once you have finished using an instance to release
* acquired resources, such as memory and codecs. Once you have called {@link #release}, you
* must no longer interact with the released instance.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f1e60387340e..aa307485c32e 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -984,13 +984,13 @@ public class MediaRecorder implements AudioRouting,
* after setVideoSource(). Call this after setOutputFormat() but before
* prepare().
*
+ * <p>NOTE: On some devices that have auto-frame rate, this sets the
+ * maximum frame rate, not a constant frame rate. Actual frame rate
+ * will vary according to lighting conditions.</p>
+ *
* @param rate the number of frames per second of video to capture
* @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat().
- *
- * NOTE: On some devices that have auto-frame rate, this sets the
- * maximum frame rate, not a constant frame rate. Actual frame rate
- * will vary according to lighting conditions.
*/
public native void setVideoFrameRate(int rate) throws IllegalStateException;
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 3349277ede3b..f3dfeb665cc7 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -17,6 +17,7 @@
package android.media.audiofx;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.AttributionSource.ScopedParcelState;
@@ -110,10 +111,18 @@ public class Visualizer {
public static final int MEASUREMENT_MODE_NONE = 0;
/**
- * Defines a measurement mode which computes the peak and RMS value in mB, where 0mB is the
- * maximum sample value, and -9600mB is the minimum value.
- * Values for peak and RMS can be retrieved with
- * {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
+ * Defines a measurement mode which computes the peak and RMS value in mB below the
+ * "full scale", where 0mB is normally the maximum sample value (but see the note
+ * below). Minimum value depends on the resolution of audio samples used by the audio
+ * framework. The value of -9600mB is the minimum value for 16-bit audio systems and
+ * -14400mB or below for "high resolution" systems. Values for peak and RMS can be
+ * retrieved with {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
+ *
+ * <p class=note><strong>Note:</strong> when Visualizer effect is attached to the
+ * global session (with session ID 0), it is possible to observe RMS peaks higher than
+ * 0 dBFS, for example in the case when there are multiple audio sources playing
+ * simultaneously. In this case {@link #getMeasurementPeakRms(MeasurementPeakRms)}
+ * method can return a positive value.
*/
public static final int MEASUREMENT_MODE_PEAK_RMS = 1 << 0;
@@ -183,17 +192,17 @@ public class Visualizer {
* Handler for events coming from the native code
*/
@GuardedBy("mListenerLock")
- private Handler mNativeEventHandler = null;
+ @Nullable private Handler mNativeEventHandler = null;
/**
* PCM and FFT capture listener registered by client
*/
@GuardedBy("mListenerLock")
- private OnDataCaptureListener mCaptureListener = null;
+ @Nullable private OnDataCaptureListener mCaptureListener = null;
/**
* Server Died listener registered by client
*/
@GuardedBy("mListenerLock")
- private OnServerDiedListener mServerDiedListener = null;
+ @Nullable private OnServerDiedListener mServerDiedListener = null;
// accessed by native methods
private long mNativeVisualizer; // guarded by a static lock in native code
@@ -618,7 +627,7 @@ public class Visualizer {
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_INIT} or {@link #ERROR_BAD_VALUE} in case of failure.
*/
- public int setDataCaptureListener(OnDataCaptureListener listener,
+ public int setDataCaptureListener(@Nullable OnDataCaptureListener listener,
int rate, boolean waveform, boolean fft) {
if (listener == null) {
// make sure capture callback is stopped in native code
@@ -678,7 +687,7 @@ public class Visualizer {
* <p>Call this method with a null listener to stop receiving server death notifications.
* @return {@link #SUCCESS} in case of success,
*/
- public int setServerDiedListener(OnServerDiedListener listener) {
+ public int setServerDiedListener(@Nullable OnServerDiedListener listener) {
synchronized (mListenerLock) {
mServerDiedListener = listener;
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 149c2f471a4c..04d28e7ddd91 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -60,7 +60,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -484,7 +483,7 @@ public final class TvInputManager {
private final Object mLock = new Object();
// @GuardedBy("mLock")
- private final List<TvInputCallbackRecord> mCallbackRecords = new LinkedList<>();
+ private final List<TvInputCallbackRecord> mCallbackRecords = new ArrayList<>();
// A mapping from TV input ID to the state of corresponding input.
// @GuardedBy("mLock")
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 43d4605209dc..88ca30ceb8a6 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -50,8 +50,8 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -302,7 +302,7 @@ public final class TvInteractiveAppManager {
new SparseArray<>();
// @GuardedBy("mLock")
- private final List<TvInteractiveAppCallbackRecord> mCallbackRecords = new LinkedList<>();
+ private final List<TvInteractiveAppCallbackRecord> mCallbackRecords = new ArrayList<>();
// A sequence number for the next session to be created. Should be protected by a lock
// {@code mSessionCallbackRecordMap}.
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 18b779fa7c57..e3e200fcd754 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -129,6 +129,7 @@ cc_library_shared {
cc_library_shared {
name: "libmedia_jni_utils",
srcs: [
+ ":libgui_frame_event_aidl",
"android_media_Utils.cpp",
],
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index 193a5d4f3dc0..d0f1ec6064c1 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -60,6 +60,7 @@ status_t Visualizer::set(int32_t priority,
SL_IID_VISUALIZATION, nullptr, priority, cbf, user, sessionId, io, device, probe);
if (status == NO_ERROR || status == ALREADY_EXISTS) {
initCaptureSize();
+ initSampleRate();
}
return status;
}
@@ -413,6 +414,16 @@ uint32_t Visualizer::initCaptureSize()
return size;
}
+void Visualizer::initSampleRate()
+{
+ audio_config_base_t inputConfig, outputConfig;
+ status_t status = getConfigs(&inputConfig, &outputConfig);
+ if (status == NO_ERROR) {
+ mSampleRate = outputConfig.sample_rate * 1000;
+ }
+ ALOGV("%s sample rate %d status %d", __func__, mSampleRate, status);
+}
+
void Visualizer::controlStatusChanged(bool controlGranted) {
if (controlGranted) {
// this Visualizer instance regained control of the effect, reset the scaling mode
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index c402c10ccae1..3d5d74a99d0e 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -170,6 +170,7 @@ private:
status_t doFft(uint8_t *fft, uint8_t *waveform);
void periodicCapture();
uint32_t initCaptureSize();
+ void initSampleRate();
Mutex mCaptureLock;
uint32_t mCaptureRate = CAPTURE_RATE_DEF;
diff --git a/media/jni/audioeffect/android_media_SourceDefaultEffect.cpp b/media/jni/audioeffect/android_media_SourceDefaultEffect.cpp
index d244bcb71c62..e568db1283fc 100644
--- a/media/jni/audioeffect/android_media_SourceDefaultEffect.cpp
+++ b/media/jni/audioeffect/android_media_SourceDefaultEffect.cpp
@@ -72,7 +72,7 @@ static jint android_media_SourceDefaultEffect_native_setup(JNIEnv *env,
goto setup_exit;
}
- nId = reinterpret_cast<jint *>(env->GetPrimitiveArrayCritical(jId, NULL));
+ nId = env->GetIntArrayElements(jId, nullptr /* isCopy */);
if (nId == NULL) {
ALOGE("setup: Error retrieving id pointer");
lStatus = BAD_VALUE;
@@ -98,7 +98,7 @@ setup_exit:
// Final cleanup and return.
if (nId != NULL) {
- env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ env->ReleaseIntArrayElements(jId, nId, 0 /* mode */);
nId = NULL;
}
diff --git a/media/jni/audioeffect/android_media_StreamDefaultEffect.cpp b/media/jni/audioeffect/android_media_StreamDefaultEffect.cpp
index accdddbc97eb..f276f48315d9 100644
--- a/media/jni/audioeffect/android_media_StreamDefaultEffect.cpp
+++ b/media/jni/audioeffect/android_media_StreamDefaultEffect.cpp
@@ -72,7 +72,7 @@ static jint android_media_StreamDefaultEffect_native_setup(JNIEnv *env,
goto setup_exit;
}
- nId = reinterpret_cast<jint *>(env->GetPrimitiveArrayCritical(jId, NULL));
+ nId = env->GetIntArrayElements(jId, nullptr /* isCopy */);
if (nId == NULL) {
ALOGE("setup: Error retrieving id pointer");
lStatus = BAD_VALUE;
@@ -98,7 +98,7 @@ setup_exit:
// Final cleanup and return.
if (nId != NULL) {
- env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ env->ReleaseIntArrayElements(jId, nId, 0 /* mode */);
nId = NULL;
}
@@ -115,7 +115,7 @@ setup_exit:
return AudioEffectJni::translateNativeErrorToJava(lStatus);
}
-static void android_media_StreamDefaultEffect_native_release(JNIEnv */*env*/,
+static void android_media_StreamDefaultEffect_native_release(JNIEnv* /*env*/,
jobject /*thiz*/,
jint id) {
status_t lStatus = AudioEffect::removeStreamDefaultEffect(id);
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 7b00f9392395..fac32e02cccd 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -443,14 +443,14 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
goto setup_failure;
}
- nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
+ nId = env->GetIntArrayElements(jId, nullptr /* isCopy */);
if (nId == NULL) {
ALOGE("setup: Error retrieving id pointer");
lStatus = VISUALIZER_ERROR_BAD_VALUE;
goto setup_failure;
}
nId[0] = lpVisualizer->id();
- env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ env->ReleaseIntArrayElements(jId, nId, 0 /* mode */);
nId = NULL;
setVisualizer(env, thiz, lpVisualizer);
@@ -467,7 +467,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
setup_failure:
if (nId != NULL) {
- env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ env->ReleaseIntArrayElements(jId, nId, 0 /* mode */);
}
if (lpJniStorage) {
@@ -660,13 +660,13 @@ android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArra
return VISUALIZER_ERROR_NO_INIT;
}
- jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
+ jbyte* nWaveform = env->GetByteArrayElements(jWaveform, nullptr /* isCopy */);
if (nWaveform == NULL) {
return VISUALIZER_ERROR_NO_MEMORY;
}
jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
- env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
+ env->ReleaseByteArrayElements(jWaveform, nWaveform, 0 /* mode */);
return status;
}
@@ -678,13 +678,13 @@ android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFf
return VISUALIZER_ERROR_NO_INIT;
}
- jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
+ jbyte* nFft = env->GetByteArrayElements(jFft, nullptr /* isCopy */);
if (nFft == NULL) {
return VISUALIZER_ERROR_NO_MEMORY;
}
jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
- env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
+ env->ReleaseByteArrayElements(jFft, nFft, 0 /* mode */);
return status;
}
diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
index 5005c46c47a8..2cba03bc5c57 100644
--- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
+++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -238,13 +238,18 @@ public abstract class RemoteDisplayProvider {
* Adds the specified remote display and notifies the system.
*
* @param display The remote display that was added.
- * @throws IllegalStateException if there is already a display with the same id.
+ * @throws IllegalStateException if the argument is null, or if there is already a display with
+ * the same id.
*/
public void addDisplay(RemoteDisplay display) {
- if (display == null || mDisplays.containsKey(display.getId())) {
- throw new IllegalArgumentException("display");
+ if (display == null) {
+ throw new IllegalArgumentException("display cannot be null");
}
- mDisplays.put(display.getId(), display);
+ String displayId = display.getId();
+ if (mDisplays.containsKey(displayId)) {
+ throw new IllegalArgumentException("display already exists with id: " + displayId);
+ }
+ mDisplays.put(displayId, display);
publishState();
}
@@ -252,11 +257,16 @@ public abstract class RemoteDisplayProvider {
* Updates information about the specified remote display and notifies the system.
*
* @param display The remote display that was added.
- * @throws IllegalStateException if the display was n
+ * @throws IllegalStateException if the argument is null, or if the provider is not aware of the
+ * display.
*/
public void updateDisplay(RemoteDisplay display) {
- if (display == null || mDisplays.get(display.getId()) != display) {
- throw new IllegalArgumentException("display");
+ if (display == null) {
+ throw new IllegalArgumentException("display cannot be null");
+ }
+ String displayId = display.getId();
+ if (mDisplays.get(displayId) != display) {
+ throw new IllegalArgumentException("unexpected display with id: " + displayId);
}
publishState();
}
@@ -265,12 +275,18 @@ public abstract class RemoteDisplayProvider {
* Removes the specified remote display and tells the system about it.
*
* @param display The remote display that was removed.
+ * @throws IllegalStateException if the argument is null, or if the provider is not aware of the
+ * display.
*/
public void removeDisplay(RemoteDisplay display) {
- if (display == null || mDisplays.get(display.getId()) != display) {
- throw new IllegalArgumentException("display");
+ if (display == null) {
+ throw new IllegalArgumentException("display cannot be null");
+ }
+ String displayId = display.getId();
+ if (mDisplays.get(displayId) != display) {
+ throw new IllegalArgumentException("unexpected display with id: " + displayId);
}
- mDisplays.remove(display.getId());
+ mDisplays.remove(displayId);
publishState();
}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 1ebdc273931b..c2afc609e947 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -80,7 +80,7 @@ ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const c
Surface* surface = static_cast<Surface*>(window);
sp<IBinder> parentHandle = surface->getSurfaceControlHandle();
- uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+ int32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
sp<SurfaceControl> surfaceControl;
if (parentHandle) {
surfaceControl =
@@ -88,11 +88,8 @@ ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const c
// Format is only relevant for buffer queue layers.
PIXEL_FORMAT_UNKNOWN /* format */, flags, parentHandle);
} else {
- surfaceControl =
- client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */,
- // Format is only relevant for buffer queue layers.
- PIXEL_FORMAT_UNKNOWN /* format */, flags,
- static_cast<Surface*>(window));
+ // deprecated, this should no longer be used
+ surfaceControl = nullptr;
}
if (!surfaceControl) {
@@ -669,6 +666,8 @@ void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* aSurfaceTransacti
AVsyncId vsyncId) {
CHECK_NOT_NULL(aSurfaceTransaction);
const auto startTime = AChoreographer_getStartTimeNanosForVsyncId(vsyncId);
- ASurfaceTransaction_to_Transaction(aSurfaceTransaction)
- ->setFrameTimelineInfo({.vsyncId = vsyncId, .startTimeNanos = startTime});
+ FrameTimelineInfo ftInfo;
+ ftInfo.vsyncId = vsyncId;
+ ftInfo.startTimeNanos = startTime;
+ ASurfaceTransaction_to_Transaction(aSurfaceTransaction)->setFrameTimelineInfo(ftInfo);
}
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index bb25274e3136..cd6ed2391608 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -25,6 +25,12 @@
#include <hwui/ImageDecoder.h>
#include <log/log.h>
#include <SkAndroidCodec.h>
+#include <SkCodec.h>
+#include <SkColorSpace.h>
+#include <SkImageInfo.h>
+#include <SkRect.h>
+#include <SkSize.h>
+#include <SkStream.h>
#include <utils/Color.h>
#include <fcntl.h>
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 16cd2e55136c..97dfba16d145 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -49,6 +49,14 @@
android:configChanges="orientation|screenSize"
android:theme="@style/ChooserActivity"/>
+ <activity
+ android:name=".CompanionDeviceDataTransferActivity"
+ android:exported="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+ android:theme="@style/ChooserActivity"/>
+
<service
android:name=".CompanionDeviceDiscoveryService"
android:exported="false" />
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 2d8ef7348dfd..03d8d50d788b 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om jou &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te bestuur"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot jou &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
<string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om programme te stroom?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Hierdie program is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê, en sal toegang hê tot jou Foon-, SMS-, Kontakte-, Kalender- en Toestelle in die Omtrek-toestemming."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programme"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot jou foon se foto\'s, media en kennisgewings"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle kennisgewings lees, insluitend inligting soos kontakte, boodskappe en foto\'s"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om programme tussen jou toestelle te stroom"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
<string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dra programtoestemmings na jou horlosie toe oor"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Om dit makliker te maak om jou horlosie op te stel, sal programme wat gedurende opstelling op jou horlosie geïnstalleer word, dieselfde toestemmings as jou foon gebruik.\n\n Hierdie toestemmings kan toegang tot jou horlosie se mikrofoon en ligging insluit."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Terug"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Gee programme op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dieselfde toestemmings as op &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dit kan mikrofoon-, kamera- en liggingtoegang insluit, asook ander sensitiewe toestemmings op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Jy kan hierdie toestemmings enige tyd verander in jou Instellings op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Program-ikoon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Meer Inligting-knoppie"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 5cb306f14380..2b106bc1c8d2 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - &lt;strong&gt;&lt;/strong&gt; እንዲያስተዳደር ይፍቀዱ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; መሣሪያ እንዲደርስ ይፍቀዱለት"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
<string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; መተግበሪያዎችን እንዲለቅቅ ይፈቀድለት?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች፣ የቀን መቁጠሪያ፣ የጥሪ ምዝገባ ማስታወሻዎች እና በአቅራቢያ ያሉ የመሣሪያዎች ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"መተግበሪያዎች"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን ስልክ ፎቶዎች፣ ሚዲያ እና ማሳወቂያዎች ለመድረስ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ ላይ እንዲደርስ ይፍቀዱለት"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"እንደ እውቂያዎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ ይችላል"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"የGoogle Play አገልግሎቶች"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን በዥረት ለመልቀቅ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
<string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"የመተግበሪያ ፈቃዶችን ወደ የእጅ ሰዓትዎ ያስተላልፉ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"የእጅ ሰዓትዎን ማቀናበርን ለማቅለል በማዋቀር ጊዜ በእጅ ሰዓትዎ ላይ የተጫኑ መተግበሪያዎች እንደ ስልክዎ ተመሳሳይ ፈቃዶችን ይጠቀማሉ።\n\n እነዚህ ፈቃዶች የእጅ ሰዓትዎ ማይክሮፎን እና አካባቢ መዳረሻን ሊያካትቱ ይችላሉ።"</string>
+ <string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ላይ ላሉ መተግበሪያዎች በ&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ላይ ካሉት ጋር ተመሳሳይ ፈቃዶች ይሰጣቸው?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ይህ የማይክሮፎን፣ የካሜራ እና የአካባቢ መዳረሻ እና ሌሎች በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; ላይ ያሉ አደገኛ ፈቃዶችን ሊያካትት ይችላል።እነዚህን ፈቃዶች በማንኛውም ጊዜ በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;ላይ ቅንብሮችዎ ውስጥ መቀየር ይችላሉ።"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"የመተግበሪያ አዶ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"የተጨማሪ መረጃ አዝራር"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index b4c74ad07e40..eca3b573ceba 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
- <string name="confirmation_title" msgid="8455544820286920304">"‏السماح للتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بإدارة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
<string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ببث التطبيقات؟"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"هذا التطبيق مطلوب لإدارة <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. سيتم السماح لتطبيق <xliff:g id="APP_NAME">%2$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم وسجلّات المكالمات والأجهزة المجاورة."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"التطبيقات"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"بث تطبيقات هاتفك"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"تطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> للوصول إلى الصور والوسائط والإشعارات في هاتفك."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"يطلب التطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> لمشاركة التطبيقات بين أجهزتك."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
<string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"نقل أذونات التطبيقات إلى ساعتك"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"لتسهيل إعداد ساعتك، فإن التطبيقات التي يتم تثبيتها على ساعتك أثناء الإعداد ستستخدم الأذونات نفسها التي يستخدمها هاتفك.\n\n قد تشتمل هذه الأذونات على الوصول إلى ميكروفون ساعتك وبيانات موقعها الجغرافي."</string>
+ <string name="consent_back" msgid="2560683030046918882">"رجوع"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏هل تريد منح التطبيقات على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; نفس الأذونات على &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;قد تتضمَّن هذه الأذونات الوصول إلى الميكروفون والكاميرا والموقع الجغرافي وغيرها من أذونات الوصول إلى المعلومات الحسّاسة على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;يمكنك تغيير هذه الأذونات في أي وقت في إعداداتك على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"رمز التطبيق"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"زر مزيد من المعلومات"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index b2865dc79ad5..fcdd8cddce3f 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; পৰিচালনা কৰিবলৈ দিয়ক"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; এক্সেছ কৰিবলৈ দিয়ক"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এপ্লিকেশ্বন ষ্ট্ৰীম কৰিবলৈ অনুমতি দিবনে?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্‌টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক ,কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"এপ্‌"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"আপোনাৰ ফ’নৰ এপ্‌ ষ্ট্ৰীম কৰক"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ফ’নৰ ফট’, মিডিয়া আৰু জাননী এক্সেছ কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"জাননী"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"সম্পৰ্কসূচী, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়িব পাৰে"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্‌ ষ্ট্ৰীম কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
<string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"আপোনাৰ ঘড়ীলৈ এপৰ অনুমতিসমূহ স্থানান্তৰ কৰক"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"আপোনাৰ ঘড়ীটো ছেটআপ কৰাটো অধিক সহজ কৰি তুলিবলৈ, এয়া কৰাৰ সময়ত আপোনাৰ ঘড়ীটোত ইনষ্টল কৰি থোৱা এপ্‌সমূহে আপোনাৰ ফ’নৰ দৰে একেই অনুমতিসমূহ ব্যৱহাৰ কৰিব।\n\n এই অনুমতিসমূহত আপোনাৰ ঘড়ীৰ মাইক্ৰ’ফ’ন আৰু অৱস্থানৰ এক্সেছ অন্তৰ্ভুক্ত হ’ব পাৰে।"</string>
+ <string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"এপ্‌সমূহক &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ত দিয়াৰ দৰে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;তো একে অনুমতি প্ৰদান কৰিবনে?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ইয়াত &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ত মাইক্ৰ’ফ’ন, কেমেৰা আৰু অৱস্থানৰ এক্সেছ আৰু অন্য সংবেদশীল অনুমতিসমূহ প্ৰদান কৰাটো অন্তৰ্ভুক্ত হ’ব পাৰে।&lt;/p&gt; &lt;p&gt;আপুনি যিকোনো সময়তে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ত থকা আপোনাৰ ছেটিঙত এই অনুমতিসমূহ সলনি কৰিব পাৰে।&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"এপৰ চিহ্ন"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"অধিক তথ্যৰ বুটাম"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index e8e4e7631481..e8c11e84d492 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı idarə etməsinə icazə verin"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınıza girişinə icazə verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin tətbiqlərdə yayım etməsinə icazə verilsin?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihaz icazələrinə giriş əldə edəcək."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından telefonunuzun fotoları, mediası və bildirişlərinə giriş üçün icazə istəyir"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Bütün bildirişləri, o cümlədən kontaktlar, mesajlar və fotolar kimi məlumatları oxuya bilər"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından cihazlarınız arasında tətbiqləri yayımlamaq üçün icazə istəyir"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
<string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Tətbiq icazələrini saatınıza köçürün"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Saatınızı ayarlamağı asanlaşdırmaq üçün ayarlama zamanı saatınızda quraşdırılmış tətbiqlər telefonunuzla eyni icazələrdən istifadə edəcək.\n\n Bu icazələrə saatınızın mikrofonuna və məkanına giriş daxil ola bilər."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındakı tətbiqlərə &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakılarla eyni icazələr verilsin?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Buraya &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; cihazındakı Mikrofon, Kamera və Məkana girişi və digər həssas icazələr daxil ola bilər.&lt;/p&gt; &lt;p&gt;Bu icazələri istənilən vaxt &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; cihazında ayarlarınızda dəyişə bilərsiniz.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Tətbiq İkonası"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Ətraflı Məlumat Düyməsi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 5d98a13e660e..37f96c37c210 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Želite da dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da strimuje aplikacije?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, kalendar, evidencije poziva i uređaje u blizini."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Može da čita sva obaveštenja, uključujući informacije poput kontakata, poruka i slika"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za strimovanje aplikacija između uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenesite dozvole za aplikacije na sat"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Da bismo pojednostavili podešavanje sata, aplikacije instalirane na satu tokom podešavanja će koristiti iste dozvole kao telefon.\n\n Te dozvole mogu da obuhvataju pristup mikrofonu i lokaciji sata."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Aplikcijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dajte sve dozvole kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To može da obuhvata pristup mikrofonu, kameri i lokaciji, kao i drugim osetljivim dozvolama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;U svakom trenutku možete da promenite te dozvole u Podešavanjima na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Dugme za više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 3a57bcc34fb6..559fa9450027 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ да вашай прылады &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; перадаваць праграмы плынню?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі тэлефон падключаны)."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на планшэце &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі планшэт падключаны)."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на прыладзе &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі прылада падключана)."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа ўзаемадзейнічаць з вашымі апавяшчэннямі і атрымае доступ да тэлефона, SMS, кантактаў, календара, журналаў выклікаў і прылад паблізу."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Праграмы"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Трансліруйце змесціва праграм з вашага тэлефона"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на доступ да фота, медыяфайлаў і апавяшчэнняў вашага тэлефона"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Можа счытваць усе апавяшчэнні, уключаючы паведамленні, фота і інфармацыю пра кантакты"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Сэрвісы Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на перадачу праграм плынню паміж вашымі прыладамі"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перанос дазволаў праграм на ваш гадзіннік"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Для праграм, усталяваных на гадзіннік падчас наладжвання, будуць дзейнічаць тыя самыя дазволы, што і на тэлефоне.\n\n Так гадзіннік можа атрымаць доступ да мікрафона і даных пра месцазнаходжанне."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Даць праграмам на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; такія самыя дазволы, што і на прыладзе &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Дазволы могуць уключаць доступ да мікрафона, камеры і даных пра месцазнаходжанне, а таксама да іншай канфідэнцыяльнай інфармацыі на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Вы можаце ў любы час змяніць гэтыя дазволы ў Наладах на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Значок праграмы"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка \"Даведацца больш\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index d29a9081afc0..5e34bc754c64 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Разрешаване на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството ви &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Разрешаване на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до устройството ви &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно приложения?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите, календара, списъците с обажданията и разрешенията за устройства в близост."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Поточно предаване на приложенията на телефона ви"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за достъп до снимките, мултимедията и известията на телефона ви"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Известия"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Може да чете всички известия, включително различна информация, като например контакти, съобщения и снимки"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Услуги за Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> да предава поточно приложения между устройствата ви"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
<string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Прехвърляне на разрешенията за приложенията към часовника"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"За по-лесно конфигуриране на часовника ви приложенията, инсталирани на него по време на настройването, ще използват същите разрешения като предоставените на телефона ви.\n\nТе може да включват достъп до микрофона и местоположението на часовника ви."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Искате ли да дадете на приложенията на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; същите разрешения както на &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Това може да включва достъп до микрофона, камерата и местоположението, както и други разрешения за достъп до поверителна информация на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Можете да промените тези разрешения по всяко време от настройките на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на приложението"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Бутон за още информация"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 7d0b097f2a99..381d5101a49e 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"আপনার &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; -কে অনুমতি দিন"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"আপনার &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; অ্যাক্সেস করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দিন"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"অ্যাপ্লিকেশন স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে অনুমতি দেবেন?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"এই অ্যাপকে আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে দিতে হবে। <xliff:g id="APP_NAME">%2$s</xliff:g>-কে আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট এবং ফোন, এসএমএস, পরিচিতি, ক্যালেন্ডার, কল লগ ও আশেপাশের ডিভাইস অ্যাক্সেস করার অনুমতি দেওয়া হবে।"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"অ্যাপ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"আপনার ফোনের অ্যাপ স্ট্রিমিংয়ের মাধ্যমে কাস্ট করুন"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"আপনার ফোনের ফটো, মিডিয়া এবং তথ্য অ্যাক্সেস করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"সব বিজ্ঞপ্তি পড়তে পারবে, যার মধ্যে পরিচিতি, মেসেজ ও ফটোর মতো তথ্য অন্তর্ভুক্ত"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play পরিষেবা"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"আপনার ডিভাইসগুলির মধ্যে অ্যাপ স্ট্রিম করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
<string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"অ্যাপকে দেওয়া অনুমতি আপনার ঘড়িতে ট্রান্সফার করুন"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ঘড়ি আরও সহজে সেট আপ করতে, সেট আপ চলাকালীন আপনার ঘড়িতে ইনস্টল করা অ্যাপ ফোনের মতো একই অনুমতি ব্যবহার করবে।\n\n এইসব অনুমতির মধ্যে আপনার ঘড়ির মাইক্রোফোন ও লোকেশন সম্পর্কে তথ্যের অ্যাক্সেস অন্তর্ভুক্ত থাকতে পারে।"</string>
+ <string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-এ যে অনুমতি দেওয়া আছে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-এও সেই একই অনুমতি দিতে চান?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;এটি &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&amp;gt-এ হয়ত মাইক্রোফোন, ক্যামেরা এবং লোকেশনের অ্যাক্সেস ও অন্যান্য সংবেদনশীল অনুমতি অন্তর্ভুক্ত করতে পারে;আপনি যেকোনও সময় &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;-এর \'সেটিংস\'-এ গিয়ে এইসব অনুমতি পরিবর্তন করতে পারবেন"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"অ্যাপের আইকন"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"আরও তথ্য সংক্রান্ত বোতাম"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index a723da8f59a4..5c57571fd431 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Dozvoliti da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prenosi aplikacije?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ova aplikacija je potrebna za upravljanje profilom: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte, Kalendar, Zapisnike poziva i Uređaje u blizini."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s telefona"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i odobrenjima na vašem telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s vašeg telefona"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa ovim informacijama s vašeg telefona"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sva obavještenja, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije između vaših uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos odobrenja za aplikaciju na sat"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Radi lakšeg postavljanja sata, aplikacije instalirane na satu tokom postavljanja će koristiti ista odobrenja kao i na telefonu.\n\n Ta odobrenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ista odobrenja kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ovo može uključivati pristup mikrofonu, kameri i lokaciji i druga osjetljiva odobrenja na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Uvijek možete promijeniti ova odobrenja u Postavkama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Dugme Više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index de7e2256ede8..80665cc7a8bc 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni el teu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi aplicacions en continu?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Aquesta aplicació es necessita per gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al calendari, als registres de trucades i als dispositius propers."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) per accedir a les fotos, el contingut multimèdia i les notificacions del telèfon"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Pot llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) per reproduir en continu aplicacions entre els dispositius"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
<string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfereix els permisos de les aplicacions al teu rellotge"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitar la configuració del rellotge, les aplicacions instal·lades al rellotge durant la configuració utilitzaran els mateixos permisos que al teu telèfon.\n\n Aquests permisos poden incloure l\'accés al micròfon i a la ubicació del rellotge."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Enrere"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vols concedir a les aplicacions del dispositiu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; els mateixos permisos que tenen a &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Això pot incloure accés al micròfon, a la càmera i a la ubicació, i altres permisos sensibles a &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Pots canviar aquests permisos en qualsevol moment a &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;, a Configuració.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icona de l\'aplicació"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botó Més informació"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index f195e54f743c..ac4dadcdbf1b 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k vašemu zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům, kalendáři, seznamům hovorů a zařízením v okolí."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění k přístupu k fotkám, médiím a oznámením v telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Může číst veškerá oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění ke streamování aplikací mezi zařízeními"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Přesunout oprávnění aplikací do hodinek"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Abychom vám usnadnili nastavení hodinek, aplikace nainstalované do hodinek během úvodního nastavení budou používat stejná oprávnění jako váš telefon.\n\n Tato oprávnění mohou zahrnovat přístup k mikrofonu a poloze hodinek."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Zpět"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Udělit aplikacím v zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; stejné oprávnění jako v zařízení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Může být zahrnut přístup k mikrofonu, fotoaparátu a poloze a další citlivá oprávnění na zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Tato oprávnění můžete v Nastavení na zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; kdykoliv změnit.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikace"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Tlačítko Další informace"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index a2aa5dddb43c..0e7a5b741b0c 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillad at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; kan administrere: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til dit &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når telefonen har forbindelse til internettet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når tabletten har forbindelse til internettet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når enheden har forbindelse til internettet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Du skal bruge denne app for at administrere dit <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og får adgang til dine tilladelser Opkald, Sms, Kalender, Opkaldshistorik og Enheder i nærheden."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Giv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til disse oplysninger fra din telefon"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at få adgang til din telefons billeder, medier og notifikationer"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til disse oplysninger fra din telefon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kan læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at streame apps mellem dine enheder"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptilladelser til dit ur"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"For at gøre det nemmere at konfigurere dit ur vil de apps, der installeres under konfigurationen, anvende de samme tilladelser som din telefon.\n\n Disse tilladelser kan omfatte adgang til dit urs mikrofon og lokation."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Tilbage"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du give apps på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tilladelser som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dette kan omfatte mikrofon-, kamera- og lokationsadgang samt andre tilladelser til at tilgå følsomme oplysninger på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan til enhver tid ændre disse tilladelser under Indstillinger på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Knappen Flere oplysninger"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 2b5ab117900e..7e5857525da6 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, dein Gerät &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; zu verwalten"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, auf dein Gerät (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;) zuzugreifen"</string>
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Möchtest du &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, Apps zu streamen?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Diese App wird zur Verwaltung des Geräts „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen für „Telefon“, „SMS“, „Kontakte“, „Kalender“, „Anrufliste“ und „Geräte in der Nähe“ zugreifen."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kann alle Benachrichtigungen lesen, einschließlich Informationen wie Kontakten, Nachrichten und Fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
<string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-Berechtigungen auf Smartwatch übertragen"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Damit sich deine Smartwatch leichter einrichten lässt, erhalten die Apps, die während der Einrichtung auf deiner Smartwatch installiert werden, automatisch die gleichen Berechtigungen wie deine Smartphone-Apps.\n\n Zu diesen Berechtigungen kann der Zugriff auf das Mikrofon und den Standort deiner Smartwatch gehören."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; die gleichen Berechtigungen geben wie auf &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dazu können Berechtigungen für Mikrofon, Kamera und Standortzugriff sowie andere vertrauliche Berechtigungen auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; gehören.&lt;/p&gt;&lt;p&gt;Sie lassen sich jederzeit in den Einstellungen auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; ändern.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App-Symbol"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Weitere-Infos-Schaltfläche"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 339f85a58127..9f3b2ac47d1a 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να διαχειρίζεται τη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η ροή εφαρμογών;"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις και να έχει πρόσβαση στις άδειες Τηλέφωνο, SMS, Επαφές, Ημερολόγιο, Αρχεία καταγραφής κλήσεων και Συσκευές σε κοντινή απόσταση."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Εφαρμογές"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στο &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για πρόσβαση στις φωτογραφίες, τα αρχεία μέσων και τις ειδοποιήσεις του τηλεφώνου σας"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για ροή εφαρμογών μεταξύ των συσκευών σας"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
<string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Μεταφορά αδειών εφαρμογών στο ρολόι σας"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Για να είναι πιο εύκολη η ρύθμιση του ρολογιού σας, οι εφαρμογές που εγκαθίστανται στο ρολόι σας κατά τη ρύθμιση, θα χρησιμοποιούν τις ίδιες άδειες με το τηλέφωνό σας.\n\n Στις άδειες ενδέχεται να περιλαμβάνεται άδεια πρόσβασης στο μικρόφωνο και την τοποθεσία του ρολογιού σας."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Πίσω"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Παραχώρηση στις εφαρμογές στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; των ίδιων αδειών όπως στη συσκευή &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;;"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Αυτές μπορεί να περιλαμβάνουν πρόσβαση σε μικρόφωνο, κάμερα και τοποθεσία και άλλες άδειες πρόσβασης σε ευαίσθητες πληροφορίες στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Μπορείτε να αλλάξετε αυτές τις άδειες ανά πάσα στιγμή στις Ρυθμίσεις σας στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Εικονίδιο εφαρμογής"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Κουμπί περισσότερων πληροφορ."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index d59641111959..85a3275d8cf2 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index d59641111959..85a3275d8cf2 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index d59641111959..85a3275d8cf2 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index d59641111959..85a3275d8cf2 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 9f17a89099d6..e95cc0dc5f0c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎Companion Device Manager‎‏‎‎‏‎"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to manage your &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access your &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
<string name="profile_name_watch" msgid="576290739483672360">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎watch‎‏‎‎‏‎"</string>
<string name="chooser_title" msgid="2262294130493605839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Choose a ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to be managed by &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream applications?‎‏‎‎‏‎"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this phone when connected.‎‏‎‎‏‎"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this tablet when connected.‎‏‎‎‏‎"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this device when connected.‎‏‎‎‏‎"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎This app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.‎‏‎‎‏‎"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎Apps‎‏‎‎‏‎"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎Stream your phone’s apps‎‏‎‎‏‎"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎Cross-device services‎‏‎‎‏‎"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to access your phone’s photos, media, and notifications‎‏‎‎‏‎"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎Can read all notifications, including information like contacts, messages, and photos‎‏‎‎‏‎"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎Photos and media‎‏‎‎‏‎"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎Google Play services‎‏‎‎‏‎"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to stream apps between your devices‎‏‎‎‏‎"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎device‎‏‎‎‏‎"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎Allow‎‏‎‎‏‎"</string>
<string name="consent_no" msgid="2640796915611404382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎Don’t allow‎‏‎‎‏‎"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎Transfer app permissions to your watch‎‏‎‎‏‎"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ These permissions may include access to your watch’s microphone and location.‎‏‎‎‏‎"</string>
+ <string name="consent_back" msgid="2560683030046918882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎Back‎‏‎‎‏‎"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎Give apps on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; the same permissions as on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;?‎‏‎‎‏‎"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎&lt;p&gt;This may include Microphone, Camera, and Location access, and other sensitive permissions on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions any time in your Settings on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;.&lt;/p&gt;‎‏‎‎‏‎"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎App Icon‎‏‎‎‏‎"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎More Information Button‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 5423d3eeff87..8dff83b46048 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administre tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"¿Deseas permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; transmita aplicaciones?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Calendario, Llamadas y Dispositivos cercanos."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, el contenido multimedia y las notificaciones de tu teléfono"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluso con información como contactos, mensajes y fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para transmitir apps entre dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfiere los permisos de la app a tu reloj"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para que sea más fácil configurar tu reloj, las apps que se instalen en este durante la configuración usarán los mismos permisos que tu teléfono.\n\n Es posible que estos permisos incluyan el acceso al micrófono y a la ubicación del reloj."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Quieres otorgar a las apps de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; los mismos permisos que tienen en &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Esto puede incluir el acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles del dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puedes cambiar estos permisos en cualquier momento en la Configuración del dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícono de la app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón Más información"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index ccbdd250dad2..7233e5673db8 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; inicie aplicaciones?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este teléfono cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este tablet cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Se necesita esta aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, calendario, registros de llamadas y dispositivos cercanos."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Emite las aplicaciones de tu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, los archivos multimedia y las notificaciones de tu teléfono"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para emitir aplicaciones en otros dispositivos tuyos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir permisos de aplicaciones a tu reloj"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para configurar fácilmente tu reloj, las aplicaciones que instales en él durante la configuración usarán los mismos permisos que tengan en tu teléfono.\n\n Estos permisos pueden incluir acceso al micrófono y a la ubicación del reloj."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Dar a las aplicaciones de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; los mismos permisos que tienen en &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Esto puede incluir acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles de &lt;p&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puedes cambiar estos permisos cuando quieras en los ajustes de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icono de la aplicación"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón Más información"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index d8f1e9920736..8dcf60a171f5 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallata teie seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; teie seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; juurde pääseda"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; rakendusi voogesituse kaudu üle kanda?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Seda rakendust on vaja teie profiili <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada teie märguandeid ja pääseda juurde teie telefoni, SMS-ide, kontaktide, kalendri, kõnelogide ja läheduses olevate seadmete lubadele."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotlevad teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kõikide märguannete, sealhulgas teabe, nagu kontaktid, sõnumid ja fotod, lugemine"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
<string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Rakenduste lubade kellale ülekandmine"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Selleks et muuta kella seadistamine lihtsamaks, kasutavad teie kellas seadistamise ajal installitud rakendused samasid lubasid, mis neile telefonis antud on.\n\n Need load võivad hõlmata juurdepääsuluba kella mikrofonile ja asukohale."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Tagasi"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Kas anda rakendustele seadmes &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; samad load, mis seadmes &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;See võib hõlmata mikrofoni, kaamerat ja juurdepääsu asukohale ning muid tundlikke lube seadmes &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Võite neid lube seadme &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; seadetes igal ajal muuta.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Rakenduse ikoon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Nupp Lisateave"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index de768249916c..0db66f46ff7d 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Eman &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kudeatzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Eman &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; atzitzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
<string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Aplikazioak igortzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da aplikazio hau. Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroa eta inguruko gailuak atzitzeko baimenak izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu baterako baino gehiagotarako zerbitzuak"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak atzitzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Eman informazio hori telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
<string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferitu aplikazio-baimenak erlojura"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena atzitzeko baimenak egotea."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atzera"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; gailuan dituzten baimen berberak eman nahi dizkiezu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; gailuko aplikazioei?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Haien artean, baliteke &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; gailuaren mikrofonoa, kamera, kokapenerako sarbidea eta beste kontuzko baimen batzuk egotea.&lt;/p&gt; &lt;p&gt;Baimen horiek edonoiz alda ditzakezu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; gailuaren ezarpenetan.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Aplikazioaren ikonoa"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Informazio gehiagorako botoia"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 65ed2dde864f..d9d64afe9ca6 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"‏مجاز کردن &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای مدیریت کردن &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه دهید به &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی داشته باشد"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها را جاری‌سازی کند؟"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این تلفن دسترسی داشته باشد."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این رایانه لوحی دسترسی داشته باشد."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این دستگاه دسترسی داشته باشد."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="APP_NAME">%2$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارش‌های تماس» و «دستگاه‌های اطراف» دسترسی خواهد داشت."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"برنامه‌ها"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"جاری‌سازی برنامه‌های تلفن"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"‏اجازه دادن به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای دسترسی به اطلاعات تلفن"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویس‌های بین‌دستگاهی"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه می‌خواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> به عکس‌ها، رسانه، و اعلان‌های تلفن شما دسترسی پیدا کند"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; مجاز می‌شود به این اطلاعات در دستگاهتان دسترسی پیدا کند"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل مخاطبین، پیام‌ها، و عکس‌ها را بخواند"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"عکس‌ها و رسانه‌ها"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه می‌خواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> برنامه‌ها را بین دستگاه‌های شما جاری‌سازی کند"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
- <string name="consent_yes" msgid="8344487259618762872">"مجاز است"</string>
+ <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string>
<string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"انتقال اجازه‌های برنامه به ساعت"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"برای آسان‌تر کردن راه‌اندازی ساعت، برنامه‌های نصب‌شده در ساعت درحین راه‌اندازی از همان اجازه‌های تلفن استفاده خواهند کرد.\n\n ممکن است این اجازه‌ها شامل دسترسی به میکروفون و مکان ساعت باشد."</string>
+ <string name="consent_back" msgid="2560683030046918882">"برگشت"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏به برنامه‌های موجود در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; همان اجازه‌های &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; داده شود؟"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;این اجازه‌ها می‌تواند شامل دسترسی به «میکروفون»، «دوربین»، و «مکان»، و دیگر اجازه‌های حساس در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; شود.&lt;/p&gt; &lt;p&gt;هروقت بخواهید می‌توانید این اجازه‌ها را در «تنظیمات» در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; تغییر دهید.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"نماد برنامه"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"دکمه اطلاعات بیشتر"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index c8dbeb54402a..bb4e9a58ac78 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; voi hallinnoida tätä laitettasi: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn laitteeseesi: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata sovelluksia?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Profiilin (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, kalenteriin, puhelulokeihin ja lähellä olevat laitteet ‑lupiin."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn näihin puhelimesi tietoihin"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteeltasi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) lupaa päästä puhelimesi kuviin, mediaan ja ilmoituksiin"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Voi lukea kaikkia ilmoituksia, esim. kontakteihin, viesteihin ja kuviin liittyviä tietoja"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteeltasi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) lupaa striimata sovelluksia laitteidesi välillä"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
<string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Siirrä sovellusluvat kelloon"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Sovellukset, jotka on asennettu kelloon käyttöönoton aikana, käyttävät samoja lupia kuin puhelin. Näin kello on helpompi ottaa käyttöön.\n\n Näihin lupiin saattaa kuulua pääsy kellon mikrofoniin ja sijaintiin."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Takaisin"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Anna laitteen &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sovelluksille samat luvat kuin laitteella &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Tähän voi kuulua pääsy mikrofoniin, kameraan ja sijaintiin sekä muita arkaluontoisia lupia laitteella &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Voit muuttaa lupia asetuksista milloin tahansa laitteella &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Sovelluskuvake"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Lisätietopainike"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 3d5898b0a5a9..4cd93fa9b92a 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permettre à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de diffuser des applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Cette application est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations suivantes : téléphone, messages texte, contacts, agenda, journaux d\'appels et appareils à proximité."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Applications"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre téléphone"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'application à votre montre"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Pour faciliter la configuration de votre montre, les applications installées sur celle-ci reprennent les mêmes autorisations que celles installées sur votre téléphone.\n\n Ces autorisations peuvent comprendre l\'accès au microphone et à la position de votre montre."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applications sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; les autorisations déjà accordées sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Cela peut comprendre l\'accès au microphone, à l\'appareil photo et à la position, ainsi que d\'autres autorisations sensibles sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Vous pouvez modifier ces autorisations en tout temps dans vos paramètres sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icône de l\'application"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Bouton En savoir plus"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index ecd89aa97ec9..af7d83b95fc1 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser des applis en streaming ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand ce téléphone est connecté à Internet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cette tablette est connectée à Internet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cet appareil est connecté à Internet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Cette appli est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts, à l\'agenda, aux journaux d\'appels et aux appareils à proximité."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Applis"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Diffuser en streaming les applis de votre téléphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris des informations comme les contacts, messages et photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour caster des applis d\'un appareil à l\'autre"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'appli vers la montre"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Pour que votre montre soit plus facile à configurer, les applis qui y sont installées pendant la configuration utiliseront les mêmes autorisations que votre téléphone.\n\n Il peut s\'agir, par exemple, de l\'accès au micro et à la position de votre montre."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder les mêmes autorisations aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; que sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Il peut s\'agir de l\'accès au micro, à l\'appareil photo et à la position, et d\'autres autorisations sensibles sur l\'appareil &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Vous pouvez modifier ces autorisations à tout moment dans les paramètres de l\'appareil &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icône d\'application"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Bouton Plus d\'informations"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index d060f29a7e02..8eae0cb40da8 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; xestione o teu dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda ao teu dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita aplicacións noutros dispositivos?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Esta aplicación é necesaria para xestionar o teu dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do calendario, dos rexistros de chamadas e dos dispositivos próximos."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para acceder ás fotos, ao contido multimedia e ás notificacións do teléfono"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para emitir aplicacións entre os teus aparellos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir os permisos de aplicacións ao reloxo"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para que che resulte máis doado configurar o reloxo, as aplicacións que instales nel durante a configuración usarán os mesmos permisos que o teléfono.\n\n Entre estes permisos poden estar incluídos os de acceso ao micrófono e á localización do teléfono."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Queres darlles ás aplicacións de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; os mesmos permisos que teñen as de &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Con esta acción podes conceder acceso ao micrófono, á cámara e á localización, así como outros permisos de acceso á información confidencial de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Podes cambiar estes permisos en calquera momento na configuración de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icona de aplicación"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón de máis información"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index d06d8c677fd4..1186eddd650a 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"તમારા &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને મેનેજ કરવા માટે &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂર કરો"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"તમારા &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને ઍક્સેસ કરવાની &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"શું &lt;/strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને ઍપ્લિકેશનો સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"તમારી <xliff:g id="DEVICE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો, કૅલેન્ડર, કૉલ લૉગ અને નજીકનાં ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ઍપ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ફોનના ફોટા, મીડિયા અને નોટિફિકેશન ઍક્સેસ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચી શકે છે"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
<string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"તમારી ઘડિયાળમાં ઍપ પરવાનગીઓ ટ્રાન્સફર કરો"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"તમારી ઘડિયાળનું સેટઅપ કરવાનું સરળ બનાવવા માટે, સેટઅપ દરમિયાન તમારી ઘડિયાળ પર ઇન્સ્ટૉલ કરેલી ઍપ દ્વારા તમારા ફોન પર મળેલી પરવાનગીઓનો ઉપયોગ કરવામાં આવશે.\n\n આ પરવાનગીઓમાં તમારી ઘડિયાળના માઇક્રોફોન અને સ્થાન સંબંધિત માહિતીનો ઍક્સેસ શામેલ હોઈ શકે છે."</string>
+ <string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; પરની ઍપને &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; પર છે તે જ પરવાનગીઓ આપીએ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;આમાં &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; પરના માઇક્રોફોન, કૅમેરા અને સ્થાનના ઍક્સેસ તથા અન્ય સંવેદનશીલ માહિતીની પરવાનગીઓ શામેલ હોઈ શકે છે.&lt;/p&gt; &lt;p&gt;તમે &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; પર તમારા સેટિંગમાં તમે કોઈપણ સમયે આ પરવાનગીઓને બદલી શકો છો.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ઍપનું આઇકન"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"વધુ માહિતી માટેનું બટન"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 1be6af8af0ec..751333d15e3a 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को, अपनी &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मैनेज करने की अनुमति दें"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ऐक्सेस करने की अनुमति दें"</string>
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से प्रबंधित किया जा सके"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> को मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, इसे आपके फ़ोन, एसएमएस, संपर्कों, कैलेंडर, कॉल लॉग, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति मिल पाएगी."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ऐप्लिकेशन"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"अपने फ़ोन के ऐप्लिकेशन को स्ट्रीम करें"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रही हैं"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, डिवाइसों के बीच ऐप्लिकेशन को स्ट्रीम करने की अनुमति मांग रहा है"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ऐप्लिकेशन से जुड़ी अनुमतियों को अपनी वॉच में ट्रांसफ़र करें"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"वॉच को सेट अप करने की प्रोसेस को आसान बनाने के लिए, उस पर इंस्टॉल किए गए ऐप्लिकेशन को भी वही अनुमतियां मिलेंगी जो आपने उन ऐप्लिकेशन को फ़ोन पर दी होंगी.\n\n इन अनुमतियों में, आपकी वॉच के माइक्रोफ़ोन और जगह की जानकारी का ऐक्सेस शामिल हो सकता है."</string>
+ <string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"क्या &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; पर ऐप्लिकेशन को वही अनुमतियां देनी हैं जो &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; पर दी हैं?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;इसमें &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; पर मौजूद माइक्रोफ़ोन, कैमरा, जगह की जानकारी को ऐक्सेस करने, और अन्य संवेदनशील जानकारी ऐक्सेस करने की अनुमतियां शामिल हो सकती हैं.&lt;/p&gt; &lt;p&gt;किसी भी समय &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; की सेटिंग में जाकर, इन अनुमतियों में बदलाव किए जा सकते हैं.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ऐप्लिकेशन आइकॉन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ज़्यादा जानकारी वाला बटन"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 610b7bdffa70..224bf69200f6 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa vašem uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pokretanje streama aplikacija?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> da pristupi fotografijama, medijskim sadržajima i obavijestima na telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sve obavijesti, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za streamanje aplikacija između vaših uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos dopuštenja aplikacije na sat"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Kako bi postavljanje sata bilo jednostavnije, aplikacije instalirane na satu će tijekom postavljanja upotrebljavati ista dopuštenja kao telefon.\n\n Ta dopuštenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Davanje jednakih dopuštenja aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kao i na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To može uključivati pristup mikrofonu, kameri i lokaciji i druga dopuštenja za osjetljive podatke na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ta dopuštenja uvijek možete promijeniti u postavkama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb Više informacija"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 625a3e9cd4aa..b06e28974f2d 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; engedélyezése a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kezelésére"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hozzáférésének engedélyezése a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszközhöz"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak appok streamelését?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre, a naptárra, a hívásnaplókra és a közeli eszközökre vonatkozó engedélyekhez."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében a telefonon tárolt fotókhoz, médiatartalmakhoz és értesítésekhez való hozzáféréshez"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében az alkalmazások eszközök közötti streameléséhez"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
<string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Alkalmazásengedélyek átvitele az órára"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Az óra beállításának megkönnyítése érdekében a beállítás során az órára telepített alkalmazások ugyanazokat az engedélyeket használják majd, mint a telefonja.\n\n Ezek az engedélyek magukban foglalhatják az óra mikrofonjához és helyadataihoz való hozzáférést."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Vissza"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ugyanolyan engedélyeket ad a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; eszközön található alkalmazásoknak, mint a(z) &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz esetén?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ide tartozhatnak a mikrofonhoz, a kamerához és a helyhez való hozzáférések, valamint a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; eszközön érvényes egyéb, bizalmas adatokra vonatkozó hozzáférési engedélyek is.&lt;/p&gt; &lt;p&gt;Ezeket az engedélyeket bármikor módosíthatja a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; eszköz beállításai között.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Alkalmazás ikonja"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"További információ gomb"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index f09441fcdb4c..1fe333193acb 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել ձեր &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել ձեր &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին բացել հավելվածներ"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը ինտերնետ կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Օրացույց», «Կանչերի ցուցակ» և «Մոտակա սարքեր» թույլտվությունները։"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Հավելվածներ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Հեռարձակել հեռախոսի հավելվածները"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր հեռախոսի լուսանկարները, մեդիաֆայլերն ու ծանուցումները տեսնելու համար"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
<string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Հավելվածների թույլտվությունների տեղափոխում ժամացույց"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Կարգավորման ժամանակ ժամացույցում տեղադրված հավելվածների համար կօգտագործվեն նույն թույլտվությունները, ինչ հեռախոսում։\n\n Այդ թույլտվությունները կարող են ներառել ժամացույցի խոսափողի կամ տեղադրության տվյալների օգտագործումը։"</string>
+ <string name="consent_back" msgid="2560683030046918882">"Հետ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; սարքում տա՞լ հավելվածներին նույն թույլտվությունները, ինչ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքում"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Դրանք կարող են ներառել խոսափողի, տեսախցիկի և տեղադրության տվյալների օգտագործման թույլտվությունները, ինչպես նաև կոնֆիդենցիալ տեղեկությունների օգտագործման այլ թույլտվություններ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; սարքում։&lt;/p&gt; &lt;p&gt;Այդ թույլտվությունները ցանկացած ժամանակ կարելի է փոխել &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; սարքի ձեր կարգավորումներում։&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Հավելվածի պատկերակ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"«Այլ տեղեկություններ» կոճակ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index ef52808cd5ff..2ee559d8726d 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengelola &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, Kalender, Log panggilan, dan Perangkat di sekitar."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikasi ponsel"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses informasi ini dari ponsel Anda"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses informasi ini dari ponsel Anda"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Dapat membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer izin aplikasi ke smartwatch"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk mempermudah penyiapan smartwatch, aplikasi yang diinstal di smartwatch selama penyiapan akan menggunakan izin yang sama dengan ponsel.\n\n Izin ini dapat meliputi akses ke mikrofon dan lokasi smartwatch."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan aplikasi di &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izin yang sama seperti di &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ini termasuk akses Mikrofon, Kamera, dan Lokasi, serta izin sensitif lainnya di &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Anda dapat mengubah izin ini kapan saja di Setelan pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikon Aplikasi"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Tombol Informasi Lainnya"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index c0ca2fcf3ba3..f694d0f3b4a9 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; stjórn á: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Þetta forrit er nauðsynlegt til að hafa umsjón með <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða, dagatals, símtalaskráa og nálægra tækja."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Forrit"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um aðgang að myndum, margmiðlunarefni og tilkynningum símans þíns fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Getur lesið allar tilkynningar, þar á meðal upplýsingar á borð við tengiliði skilaboð og myndir"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um heimild fyrir straumspilun forrita á milli tækjanna þinna fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
<string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Flytja heimildir forrita yfir í úrið"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Til að auðvelda uppsetningu úrsins munu forrit sem eru sett upp í úrinu við uppsetningu nota sömu heimildir og stilltar eru í símanum.\n\n Þessar heimildir kunna að fela í sér aðgang að hljóðnema og staðsetningu úrsins."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Veita forritum í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sömu heimildir og í &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Þetta kann að fela í sér aðgang að hljóðnema, myndavél og staðsetningu og aðrar heimildir fyrir viðkvæmu efni í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Hægt er að breyta þessum heimildum hvenær sem er í stillingunum í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Tákn forrits"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Hnappur fyrir upplýsingar"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 5f88b7a68432..952b090d57ec 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di gestire &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di riprodurre applicazioni in streaming?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo telefono quando è connesso."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo tablet quando è connesso."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Questa app è necessaria per gestire il tuo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. L\'app <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Calendar, Registri chiamate e Dispositivi nelle vicinanze."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"App"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a queste informazioni dal tuo telefono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche del telefono"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a questa informazione dal tuo telefono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Puoi leggere tutte le notifiche, incluse le informazioni come contatti, messaggi e foto"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione a trasmettere app in streaming tra i dispositivi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
<string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Trasferisci le autorizzazioni app all\'orologio"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitare la configurazione dell\'orologio, le app installate su quest\'ultimo durante la configurazione useranno le stesse autorizzazioni delle app sul telefono.\n\n Queste autorizzazioni potrebbero includere l\'accesso al microfono e alla posizione dell\'orologio."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Indietro"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vuoi dare alle app su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; le stesse autorizzazioni che hai dato su &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Potrebbero essere incluse le autorizzazioni di accesso al microfono, alla fotocamera e alla posizione, nonché altre autorizzazioni sensibili su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puoi cambiare queste autorizzazioni in qualsiasi momento nelle Impostazioni su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icona dell\'app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Pulsante Altre informazioni"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 4a811f0aef9d..00b732ad973f 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"‏אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לנהל את &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"‏אישור לאפליקציה ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;g;‎‏ לגשת אל ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎‏"</string>
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="chooser_title" msgid="2262294130493605839">"‏בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏לאפשר לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר אפליקציות?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק למכשיר &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"‏האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר, ליומן, ליומני השיחות ולמכשירים בקרבת מקום."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"אפליקציות"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"שידור אפליקציות מהטלפון"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור ה‑<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לגשת לתמונות, למדיה ולהתראות בטלפון שלך"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"התראות"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"גישת קריאה לכל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור ה‑<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לשדר אפליקציות בין המכשירים שלך"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
<string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"העברת ההרשאות הניתנות לאפליקציות אל השעון שלך"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"כדי לפשט את הגדרת השעון, אפליקציות שמותקנות במהלך ההגדרה יקבלו את אותן הרשאות שניתנו בטלפון.\n\n ההרשאות האלה עשויות לכלול גישה למיקרופון ולמיקום של השעון."</string>
+ <string name="consent_back" msgid="2560683030046918882">"חזרה"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏האם לתת לאפליקציות ב-‎&lt;strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>‏‎&lt;/strong&gt;‎‏את אותן הרשאות כמו ב-‏‎&lt;strong&gt;‎‏<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>‏‎&lt;/strong&gt;‎‏?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"‏‎&lt;p&gt;‎‏ההרשאות עשויות לכלול גישה למיקרופון, למצלמה ולמיקום, וכן גישה למידע רגיש אחר ב-‎&lt;/strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>‎&lt;/strong&gt;.&lt;/p&amp;gt‎;‎ ‎&lt;p&gt;אפשר לשנות את ההרשאות האלה בכל שלב בהגדרות של‏ ‎&lt;strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>‏‎&lt;/strong&gt;.&lt;/p&gt;‎‏"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"סמל האפליקציה"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"לחצן מידע נוסף"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 5e8d544d9b6a..c2810636ff12 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理を許可する"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; へのアクセスを許可"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; にアプリのストリーミングを許可しますか?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がスマートフォン内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がタブレット内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がデバイス内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は、通知の使用と、電話、SMS、連絡先、カレンダー、通話履歴、付近のデバイスの権限へのアクセスが可能となります。"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"アプリ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"スマートフォンのアプリのストリーミング"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってスマートフォンの写真、メディア、通知にアクセスする権限をリクエストしています"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"このスマートフォンからの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"連絡先、メッセージ、写真に関する情報を含め、すべての通知を読み取ることができます"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 開発者サービス"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってデバイス間でアプリをストリーミングする権限をリクエストしています"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"許可"</string>
<string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"スマートウォッチへのアプリの権限の移行"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"スマートウォッチのセットアップを簡単にするため、セットアップ時にスマートウォッチにインストールされたアプリに、スマートフォンと同じ権限が適用されます。\n\n これらの権限には、スマートウォッチのマイクや位置情報へのアクセス権も含まれることがあります。"</string>
+ <string name="consent_back" msgid="2560683030046918882">"戻る"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; のアプリに &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の場合と同じ権限を付与しますか?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;これには、&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; のマイク、カメラ、位置情報へのアクセスや、その他の機密情報に関わる権限が含まれる可能性があります。&lt;/p&gt; &lt;p&gt;これらの権限は &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; の [設定] でいつでも変更できます。&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"アプリのアイコン"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"詳細情報ボタン"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 3b179bf237dd..7db3d0c2ca96 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ნება დართეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/strong&gt;, რომ მართოს თქვენი &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"დაუშვით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ის&lt;/strong&gt;, წვდომა თქვენს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ზე&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"გსურთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ აპების სტრიმინგის საშუალება?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა, კალენდრის, ზარების ჟურნალისა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"აპები"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"თქვენი ტელეფონის აპების სტრიმინგი"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ წვდომა ჰქონდეს თქვენი ტელეფონის ფოტოებზე, მედიასა და შეტყობინებებზე"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტაქტები, ტექსტური შეტყობინებები და ფოტოები"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ მოწყობილობებს შორის სტრიმინგი შეძლოს"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
<string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"აპის ნებართვების საათისთვის გადაცემა"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"საათის დაყენების გასამარტივებლად თქვენს საათში დაინსტალირებული აპები იმავე ნებართვებს გამოიყენებს, რასაც ტელეფონზე იყენებს.\n\n ეს ნებართვები, შესაძლოა, მოიცავდეს თქვენი საათის მიკროფონსა და მდებარეობაზე წვდომას."</string>
+ <string name="consent_back" msgid="2560683030046918882">"უკან"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"გსურთ აპებს &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-ზე იგივე ნებართვები მიანიჭოთ, როგორიც აქვს &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;აღნიშნული შეიძლება მოიცავდეს მიკროფონზე, კამერასა და მდებარეობაზე წვდომას თუ სხვა ნებართვას სენსიტიურ ინფორმაციაზე &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;-ში.&lt;/p&gt; &lt;p&gt;ამ ნებართვების შეცვლა ნებისმიერ დროს შეგიძლიათ თქვენი პარამეტრებიდან &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;-ში.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"აპის ხატულა"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"დამატებითი ინფორმაციის ღილაკი"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index a7efb15ed0be..58a625cbad64 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беру"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын пайдалануға рұқсат беру"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына қолданбаларды трансляциялауға рұқсат етілсін бе?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы құрылғыға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына хабарландырулар жіберу, Телефон, SMS, Контактілер, Күнтізбе, Қоңырау журналдары қолданбаларын және маңайдағы құрылғыларды пайдалану рұқсаттары беріледі."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Қолданбалар"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Телефон қолданбаларын трансляциялайды."</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан телефондағы фотосуреттерді, медиафайлдар мен хабарландыруларды пайдалану үшін рұқсат сұрайды."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқи алады."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play қызметтері"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан құрылғылар арасында қолданбалар трансляциялау үшін рұқсат сұрайды."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
<string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Қолданба рұқсаттарын сағатқа ауыстыру"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Реттеу кезінде сағатқа орнатылған қолданбалар телефондағыдай рұқсаттарды пайдаланады. Осылайша сағат оңай реттеледі.\n\n Бұл рұқсаттар сағаттың микрофоны мен геодерегін пайдалануды қамтиды."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Артқа"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; құрылғысындағы қолданбаларға &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысындағыдай рұқсаттар берілсін бе?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Оларға микрофонды, камераны және геодеректі пайдалану рұқсаттары, сондай-ақ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; құрылғысына берілетін басқа да құпия ақпарат рұқсаттары кіруі мүмкін.&lt;/p&gt; &lt;p&gt;Бұл рұқсаттарды кез келген уақытта &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; құрылғысындағы параметрлерден өзгерте аласыз.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Қолданба белгішесі"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"\"Қосымша ақпарат\" түймесі"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index b18586316289..7f3b93358d04 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"កម្មវិធី​គ្រប់​គ្រង​ឧបករណ៍ដៃគូ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; គ្រប់គ្រង &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; របស់អ្នក"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើប្រាស់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; របស់អ្នក"</string>
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
<string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីឬ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតទូរសព្ទ, SMS, ទំនាក់ទំនង, ប្រតិទិន, កំណត់​ហេតុ​ហៅ​ទូរសព្ទ និងឧបករណ៍នៅជិតរបស់អ្នក។"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ផ្សាយកម្មវិធីរបស់ទូរសព្ទអ្នក"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីចូលប្រើរូបថត មេឌៀ និងការជូនដំណឹងរបស់ទូរសព្ទអ្នក"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលមើលព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ការ​ជូនដំណឹង"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"អាចអាន​ការជូនដំណឹង​ទាំងអស់ រួមទាំង​ព័ត៌មាន​ដូចជាទំនាក់ទំនង សារ និងរូបថត"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"សេវាកម្ម Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីបញ្ចាំងកម្មវិធីរវាងឧបករណ៍របស់អ្នក"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
<string name="consent_no" msgid="2640796915611404382">"កុំអនុញ្ញាត"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ផ្ទេរការអនុញ្ញាតកម្មវិធីទៅនាឡិការបស់អ្នក"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ដើម្បីជួយឱ្យការរៀបចំនាឡិការបស់អ្នកកាន់តែងាយស្រួល កម្មវិធីដែលបានដំឡើងនៅលើនាឡិការបស់អ្នកអំឡុងពេលរៀបចំនឹងប្រើការអនុញ្ញាតដូចគ្នានឹងទូរសព្ទរបស់អ្នកដែរ។\n\n ការអនុញ្ញាតទាំងនេះអាចរួមបញ្ចូលសិទ្ធិចូលប្រើទីតាំង និងមីក្រូហ្វូនរបស់នាឡិកាអ្នក។"</string>
+ <string name="consent_back" msgid="2560683030046918882">"ថយក្រោយ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ផ្ដល់​ការអនុញ្ញាតឱ្យ​កម្មវិធីនៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ដូចនៅលើ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;សកម្មភាពនេះ​អាចរួមបញ្ចូល​ការចូលប្រើ​ទីតាំង កាមេរ៉ា និងមីក្រូហ្វូន និងការអនុញ្ញាត​ដែលមានលក្ខណៈ​រសើបផ្សេងទៀត​នៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;។&lt;/p&gt; &lt;p&gt;អ្នកអាចប្ដូរ​ការអនុញ្ញាតទាំងនេះ​បានគ្រប់ពេលវេលា​នៅក្នុងការកំណត់​នៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;។&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"រូប​កម្មវិធី"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ប៊ូតុងព័ត៌មានបន្ថែម"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 64576ce8aec8..e0f2fd5eb338 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ನಿಮ್ಮ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ನಿರ್ವಹಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಅನುಮತಿಸಿ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"ನಿಮ್ಮ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, Calendar, ಕರೆಯ ಲಾಗ್‌ಗಳು ಹಾಗೂ ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ಆ್ಯಪ್‌ಗಳು"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ನಿಮ್ಮ ಫೋನ್‍ನ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಡಿವೈಸ್ ಸೇವೆಗಳು"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"ನಿಮ್ಮ ಫೋನ್‌ನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
<string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ಆ್ಯಪ್ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ ವಾಚ್‌ಗೆ ವರ್ಗಾವಣೆ ಮಾಡಿ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ನಿಮ್ಮ ವಾಚ್ ಸೆಟಪ್ ಮಾಡುವುದನ್ನು ಸುಲಭವಾಗಿಸಲು, ಸೆಟಪ್‌ನ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ವಾಚ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ ಬಳಸಿಕೊಳ್ಳುತ್ತವೆ.\n\n ಈ ಅನುಮತಿಗಳು ನಿಮ್ಮ ವಾಚ್‌ನ ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸ್ಥಳದ ಪ್ರವೇಶವನ್ನು ಒಳಗೊಳ್ಳಬಹುದು."</string>
+ <string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;/strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ &lt;/strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಆ್ಯಪ್‌ಗಳಿಗೆ ನೀಡಬೇಕೆ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ಇದು &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಮೈಕ್ರೊಫೋನ್, ಕ್ಯಾಮರಾ ಮತ್ತು ಸ್ಥಳ ಆ್ಯಕ್ಸೆಸ್ ಹಾಗೂ ಇತರ ಸೂಕ್ಷ್ಮ ಅನುಮತಿಗಳನ್ನು ಹೊಂದಿರಬಹುದು&lt;p&gt;&lt;/p&gt; &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ನಿಮ್ಮ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನೀವು ಈ ಅನುಮತಿಗಳನ್ನು ಯಾವಾಗ ಬೇಕಾದರೂ ಬದಲಾಯಿಸಬಹುದು.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ಹೆಚ್ಚಿನ ಮಾಹಿತಿಯ ಬಟನ್"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 5bf8eb4ae6ac..99acb18834df 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기를 관리하도록 허용"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 내 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기에 액세스하도록 허용"</string>
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 애플리케이션을 스트리밍하도록 허용하시겠습니까?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, Calendar, 통화 기록, 근처 기기에 대한 권한을 갖게 됩니다."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"앱"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 휴대전화의 사진, 미디어, 알림에 액세스할 수 있는 권한을 요청하고 있습니다."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"알림"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 서비스"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"허용"</string>
<string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"앱 권한을 시계로 이전"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"시계를 더 쉽게 설정하기 위해 설정하는 동안 시계에 설치된 앱에서 휴대전화와 동일한 권한을 사용합니다.\n\n 이러한 권한에는 시계의 마이크 및 위치 정보에 대한 액세스가 포함될 수 있습니다."</string>
+ <string name="consent_back" msgid="2560683030046918882">"뒤로"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;에 설치된 앱에 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 설치된 앱과 동일한 권한을 부여하시겠습니까?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;여기에는 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;에서 허용했던 마이크, 카메라, 위치 정보 액세스 권한 및 기타 민감한 권한이 포함될 수 있습니다.&lt;/p&gt; &lt;p&gt;언제든지 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;의 설정에서 이러한 권한을 변경할 수 있습니다.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"앱 아이콘"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"추가 정보 버튼"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 714dc9365bd6..4563d3741d51 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүңүздү башкарууга уруксат бериңиз"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүңүзгө кирүүгө уруксат бериңиз"</string>
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна колдонмолорду алып ойнотууга уруксат бересизби?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, байланыштар, жылнаама, чалуулар тизмеси жана жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Колдонмолор"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Телефондогу колдонмолорду алып ойнотуу"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан телефондогу сүрөттөрдү, медиа файлдарды жана билдирмелерди колдонууга уруксат сурап жатат"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуй алат"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиа"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрүңүздүн ортосунда колдонмолорду тышкы экранга чыгарууга уруксат сурап жатат"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Уруксат берүү"</string>
<string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Колдонмонун уруксаттарын саатка өткөрүү"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Сааттын жөндөлүшүн жеңилдетүү үчүн жөндөө учурунда саатыңызга орнотулган колдонмолор телефонуңуздагы уруксаттарды колдонот.\n\n Мындай уруксаттарга саатыңыздын микрофонун же жайгашкан жерин колдонуу кириши мүмкүн."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Артка"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; түзмөгүнө да &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүнө берилген уруксаттар берилсинби?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Бул уруксаттарга микрофонго, камерага жана жайгашкан жерге кирүү мүмкүнчүлүгү жана &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү башка купуя маалыматты көрүүгө уруксаттар кириши мүмкүн.&lt;/p&gt; &lt;p&gt;Бул уруксаттарды каалаган убакта &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү Жөндөөлөрдөн өзгөртө аласыз.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Колдонмонун сүрөтчөсү"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дагы маалымат баскычы"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 95cab696240f..910a527875ec 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ຈັດການ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານໄດ້"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານໄດ້"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
<string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບພລິເຄຊັນໄດ້ບໍ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ປະຕິທິນ, ບັນທຶກການໂທ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ແອັບ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອເຂົ້າເຖິງຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຂອງໂທລະສັບທ່ານ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"ສາມາດອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"ບໍລິການ Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຂອງທ່ານ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
<string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ໂອນຍ້າຍການອະນຸຍາດແອັບໄປຫາໂມງຂອງທ່ານ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ເພື່ອເຮັດໃຫ້ຕັ້ງຄ່າໂມງຂອງທ່ານໄດ້ງ່າຍຂຶ້ນ, ແອັບທີ່ຕິດຕັ້ງຢູ່ໂມງຂອງທ່ານໃນລະຫວ່າງການຕັ້ງຄ່າຈະໃຊ້ການອະນຸຍາດດຽວກັນກັບໂທລະສັບຂອງທ່ານ.\n\n ການອະນຸຍາດເຫຼົ່ານີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ ແລະ ສະຖານທີ່ຂອງທ່ານນຳ."</string>
+ <string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ໃຫ້ການອະນຸຍາດແອັບຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ເປັນການອະນຸຍາດດຽວກັນກັບຢູ່ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ນີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ, ກ້ອງຖ່າຍຮູບ ແລະ ສະຖານທີ່, ຮວມທັງການອະນຸຍາດທີ່ລະອຽດອ່ອນອື່ນໆຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;ທ່ານສາມາດປ່ຽນການອະນຸຍາດເຫຼົ່ານີ້ຕອນໃດກໍໄດ້ໃນການຕັ້ງຄ່າຂອງທ່ານຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ໄອຄອນແອັບ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ປຸ່ມຂໍ້ມູນເພີ່ມເຕີມ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 5d32fbbf9116..5edd78d0ae5a 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tvarkyti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti jūsų &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; perduoti srautu programas?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame telefone įdiegtų programų."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ši programa reikalinga norint tvarkyti jūsų „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su pranešimų funkcija ir pasiekti telefono, SMS, Kontaktų, Kalendoriaus, Skambučių žurnalų ir įrenginių netoliese leidimus."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programos"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų pasiekti telefono nuotraukas, mediją ir pranešimus"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Galima skaityti visus pranešimus, įskaitant tokią informaciją kaip kontaktai, pranešimai ir nuotraukos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš vieno įrenginio į kitą"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
<string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Laikrodžio programų perkėlimo leidimai"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Kad būtų lengviau nustatyti laikrodį, jame atliekant sąranką įdiegtoms programoms bus naudojami tie patys leidimai kaip jūsų telefone.\n\n Šie leidimai gali apimti prieigą prie laikrodžio mikrofono ir vietovės."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atgal"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Suteikti &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; esančioms programoms tuos pačius leidimus kaip &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esančioms programoms?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Gali būti įtraukti prieigos prie mikrofono, kameros ir vietovės leidimai ir kiti leidimai pasiekti neskelbtiną informaciją &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; įrenginyje.&lt;/p&gt; &lt;p&gt;Šiuos leidimus galite bet kada pakeisti „Nustatymų“ skiltyje &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; įrenginyje.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Programos piktograma"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Mygtukas „Daugiau informacijos“"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index cabfc77bb27c..582cf84e4b25 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Atļauja lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pārvaldīt ierīci &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Atļauja lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt jūsu ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vai atļaujat lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt lietojumprogrammas?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi tālrunim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi planšetdatoram &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. Lietotnei <xliff:g id="APP_NAME">%2$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas, Kalendārs, Zvanu žurnāli un Tuvumā esošas ierīces."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju piekļūt jūsu tālruņa fotoattēliem, multivides saturam un paziņojumiem šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Var lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumi un fotoattēli."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt lietotnes starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
<string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Lietotņu atļauju pārsūtīšana uz pulksteni"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Lai atvieglotu pulksteņa iestatīšanu, iestatīšanas laikā pulkstenī instalētās lietotnes saņems tādas pašas atļaujas, kādas tām ir tālrunī.\n\n Tostarp lietotnes var saņemt atļauju piekļūt pulksteņa mikrofonam un atrašanās vietai."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vai lietotnēm ierīcē &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; piešķirt tādas pašas atļaujas kā ierīcē &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Tās var būt mikrofona, kameras, atrašanās vietas piekļuves atļaujas un citas sensitīvas atļaujas ierīcē &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Atļaujas jebkurā brīdī varat mainīt ierīces &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; iestatījumos."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Lietotnes ikona"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Plašākas informācijas poga"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index b4531b5c864e..3393f360b4d3 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управува со вашиот &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до вашиот &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Да се дозволи &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримува апликации?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на телефонов кога ќе се поврзе."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на таблетов кога ќе се поврзе."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на уредов кога ќе се поврзе."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Апликацијава е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите, календарот, евиденцијата на повици и уредите во близина."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Апликации"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Стримувајте ги апликациите на телефонот"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да пристапува до фотографиите, аудиовизуелните содржини и известувањата на телефонот"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да стримува апликации помеѓу вашите уреди"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Префрлете ги дозволите за апликациите на вашиот часовник"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"За полесно поставувањето на часовникот, апликациите инсталирани на часовникот при поставувањето ќе ги користат истите дозволи како на телефонот.\n\n Овие дозволи може да опфаќаат пристап до микрофонот и локацијата на часовникот."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Дасе дадат исти дозволи на апликациите на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; како на &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ова може да вклучува пристап до микрофон, камера и локација и други чувствителни дозволи на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Може да ги промените дозволиве во секое време во вашите „Поставки“ на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на апликацијата"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Копче за повеќе информации"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 85952ca65fce..be36c5cc97f4 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"നിങ്ങളുടെ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; മാനേജ് ചെയ്യാൻ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"നിങ്ങളുടെ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്‌ലെറ്റിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. നിങ്ങളുടെ അറിയിപ്പുകളുമായി ആശയവിനിമയം നടത്താനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്‌റ്റുകൾ, കലണ്ടർ, കോൾ ചരിത്രം, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ആപ്പുകൾ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"നിങ്ങളുടെ ഫോണിലെ ഫോട്ടോകൾ, മീഡിയ, അറിയിപ്പുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിനു വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"കോൺടാക്‌റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ മുതലായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിനു വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
<string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"നിങ്ങളുടെ വാച്ചിലേക്ക് ആപ്പ് അനുമതികൾ കൈമാറുക"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"നിങ്ങളുടെ വാച്ച് സജ്ജീകരിക്കുന്നത് എളുപ്പമാക്കാൻ, സജ്ജീകരിക്കുമ്പോൾ ഫോണിലുള്ള അതേ അനുമതികൾ നിങ്ങളുടെ വാച്ചിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ഉപയോഗിക്കും.\n\n ഈ അനുമതികളിൽ നിങ്ങളുടെ വാച്ചിന്റെ മൈക്രോഫോണിലേക്കും ലോക്കേഷനിലേക്കുമുള്ള ആക്‌സസ് ഉൾപ്പെട്ടേക്കാം."</string>
+ <string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിലെ അതേ അനുമതികൾ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിലെ ആപ്പുകൾക്ക് നൽകണോ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; എന്നതിലെ മൈക്രോഫോൺ, ക്യാമറ, ലൊക്കേഷൻ ആക്‌സസ്, സെൻസിറ്റീവ് വിവരങ്ങൾക്കുള്ള മറ്റ് അനുമതികൾ എന്നിവയും ഇതിൽ ഉൾപ്പെട്ടേക്കാം&lt;p&gt;നിങ്ങൾക്ക് &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; എന്നതിലെ ക്രമീകരണത്തിൽ ഏതുസമയത്തും ഈ അനുമതികൾ മാറ്റാം."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ആപ്പ് ഐക്കൺ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"കൂടുതൽ വിവരങ്ങൾ ബട്ടൺ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index c0d589d0aca7..dc52154d2b7e 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г удирдахын тулд &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-г зөвшөөрнө үү"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-д таны &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д хандахыг зөвшөөрнө үү"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д аппуудыг дамжуулахыг зөвшөөрөх үү?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д таны мэдэгдэлтэй харилцан үйлдэл хийж, Утас, SMS, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Аппууд"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Таны утасны аппуудыг дамжуулах"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс утасны зураг, медиа болон мэдэгдэлд хандахын тулд зөвшөөрөл хүсэж байна"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Харилцагчид, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс төхөөрөмж хооронд апп дамжуулахын тулд зөвшөөрөл хүсэж байна"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
<string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Цагандаа аппын зөвшөөрлийг шилжүүлэх"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Таны цагийг тохируулахад илүү хялбар болгохын тулд тохируулгын үеэр таны цаган дээр суулгасан аппууд нь утастай тань ижил зөвшөөрлийг ашиглана.\n\n Эдгээр зөвшөөрөлд таны цагийн микрофон болон байршлын хандалт зэрэг багтаж магадгүй."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дээрх аппуудад &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; дээрхтэй адил зөвшөөрөл өгөх үү?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Үүнд Микрофон, Камер болон Байршлын хандалт болон &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; дээрх бусад эмзэг зөвшөөрөл багтаж болно.&lt;/p&gt; &lt;p&gt;Та эдгээр зөвшөөрлийг &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; дээрх Тохиргоо хэсэгтээ хүссэн үедээ өөрчлөх боломжтой.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Aппын дүрс тэмдэг"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дэлгэрэнгүй мэдээллийн товчлуур"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 0ce6ab712eb0..e5bdfd5afcab 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"तुमचे &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापित करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अनुमती द्या"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"तुमचे &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; अ‍ॅक्सेस करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अनुमती द्या"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अ‍ॅप्लिकेशन स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"तुमची <xliff:g id="DEVICE_NAME">%1$s</xliff:g> प्रोफाइल व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ॲप्स"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"फोनवरील ॲप्स स्ट्रीम करा"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"तुमच्या फोनमधील फोटो, मीडिया आणि सूचना ॲक्सेस करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचना"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीचा समावेश असलेल्या सर्व सूचना वाचू शकते"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवा"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"तुमच्या डिव्हाइसदरम्यान ॲप्स स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"अ‍ॅप परवानग्या तुमच्या वॉचवर ट्रान्सफर करा"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"तुमचे वॉच सेट करणे आणखी सोपे करण्यासाठी, सेटअपदरम्यान तुमच्या वॉचवर इंस्टॉल केलेली ॲप्स ही तुमच्या फोनप्रमाणेच परवानग्या वापरतील.\n\n या परवानग्यांमध्ये तुमच्या वॉचचा मायक्रोफोन आणि स्थानाच्या अ‍ॅक्सेसचा समावेश असू शकतो."</string>
+ <string name="consent_back" msgid="2560683030046918882">"मागे जा"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; वरील अ‍ॅप्सना &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रमाणेच परवानग्या द्यायच्या आहेत का?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;यामध्ये &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;strong&gt; वरील मायक्रोफोन, कॅमेरा आणि स्थान अ‍ॅक्सेस व इतर संवेदनशील परवानग्यांचा समावेश असू शकतो &lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;तुम्ही &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; वर तुमच्या सेटिंग्ज मध्ये या परवानग्या कधीही बदलू शकता&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"अ‍ॅप आयकन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"अधिक माहिती बटण"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 2ca812889342..70d03731816a 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengurus &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; anda"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; anda"</string>
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; menstrim aplikasi?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Kalendar, Log panggilan dan Peranti berdekatan anda."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apl"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses maklumat ini daripada telefon anda"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan telefon anda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses maklumat ini daripada telefon anda"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Pindahkan kebenaran apl pada jam tangan anda"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk memudahkan penyediaan jam tangan anda, apl yang dipasang pada jam tangan anda semasa persediaan akan menggunakan kebenaran yang sama seperti telefon anda.\n\n Kebenaran ini mungkin termasuk akses kepada mikrofon dan lokasi jam tangan anda."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan apl &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kebenaran yang sama seperti pada &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ini mungkin termasuk akses Mikrofon, Kamera dan Lokasi serta kebenaran sensitif lain pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Anda boleh menukar kebenaran ini pada bila-bila masa dalam Tetapan anda pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikon Apl"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Butang Maklumat Lagi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 1fb20bf2449e..e47e834459a3 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"သင်၏ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို စီမံခန့်ခွဲရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို ခွင့်ပြုပါ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"သင်၏ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို သုံးရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို ခွင့်ပြုပါ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"အပလီကေးရှင်းများကို တိုက်ရိုက်လွှင့်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကိုခွင့်ပြုမလား။"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်ကိုလိုအပ်သည်။ သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’၊ ‘ပြက္ခဒိန်’၊ ‘ခေါ်ဆိုမှတ်တမ်း’ နှင့် \'အနီးတစ်ဝိုက်ရှိ စက်များ\' ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"အက်ပ်များ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်လွှင့်နိုင်သည်"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်ဖုန်း၏ ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များသုံးရန် သင်၏ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
+ <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုခြင်း"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ဝန်ဆောင်မှုများ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင်၏စက်များအကြား အက်ပ်များတိုက်ရိုက်လွှင့်ရန် သင်၏ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
<string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"သင်၏နာရီသို့ အက်ပ်ခွင့်ပြုချက်များ လွှဲပြောင်းရန်"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"သင်၏နာရီ စနစ်ထည့်သွင်းရာတွင် ပိုလွယ်ကူစေရန် စနစ်ထည့်သွင်းနေစဉ်အတွင်း နာရီတွင်ထည့်သွင်းသော အက်ပ်များသည် သင့်ဖုန်းနှင့် အလားတူခွင့်ပြုချက်များကို သုံးပါမည်။\n\n ဤခွင့်ပြုချက်များတွင် သင့်နာရီ၏ မိုက်ခရိုဖုန်းနှင့် တည်နေရာတို့ကို သုံးခွင့် ပါဝင်နိုင်သည်။"</string>
+ <string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"အက်ပ်များကို &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; တွင်ပေးထားသည့် ခွင့်ပြုချက်များအတိုင်း &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; တွင် ပေးမလား။"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;၎င်းတွင် မိုက်ခရိုဖုန်း၊ ကင်မရာ၊ တည်နေရာ အသုံးပြုခွင့်အပြင် &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ပေါ်ရှိ အခြား သတိထားရမည့် ခွင့်ပြုချက်များ ပါဝင်နိုင်သည်။&lt;/p&gt; &lt;p&gt;ဤခွင့်ပြုချက်များကို &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ပေါ်ရှိ သင်၏ဆက်တင်များတွင် အချိန်မရွေးပြောင်းနိုင်သည်။&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"အက်ပ်သင်္ကေတ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"နောက်ထပ်အချက်အလက်များ ခလုတ်"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index aa73f5dff065..58d5f23838ca 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrerer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; bruker &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tillatelse til å strømme apper?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til tillatelser for telefon, SMS, kontakter, kalender, samtalelogger og enheter i nærheten."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apper"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> for å få tilgang til bilder, medier og varsler på telefonen din"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Varsler"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kan lese alle varsler, inkludert informasjon som kontakter, meldinger og bilder"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> for å strømme apper mellom enhetene dine"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptillatelser til klokken din"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"For å gjøre det enklere å konfigurere klokken din bruker apper som installeres på klokken under konfigureringen, samme tillatelser som på telefonen.\n\n Disse tillatelsene kan inkludere tilgang til mikrofonen på klokken og posisjon."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Tilbake"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du gi apper på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tillatelsene som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dette kan inkludere tilgang til mikrofon, kamera og posisjon samt andre sensitive tillatelser på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan når som helst endre disse tillatelsene i innstillingene på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Mer informasjon-knapp"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 3ba75eb31aad..a056fcc3231a 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"आफ्नो &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्ने अनुमति दिनुहोस्"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"आफ्नो &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; प्रयोग गर्ने अनुमति दिनुहोस्"</string>
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
<string name="chooser_title" msgid="2262294130493605839">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई एपहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एपलाई अनुमति दिनु पर्ने हुन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, पात्रो, कल लग तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"एपहरू"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"आफ्नो फोनका एपहरू प्रयोग गर्नुहोस्"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंको फोनमा भएका फोटो, मिडिया र सूचनाहरू हेर्ने तथा प्रयोग गर्ने अनुमति माग्दै छ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका जानकारीसहित सबै सूचनाहरू पढ्न सक्छ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"एपलाई दिइएका अनुमति घडीमा ट्रान्स्फर गर्नुहोस्"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"तपाईंको घडी सेटअप गर्ने कार्य सजिलो बनाउनका लागि सेटअप गर्ने क्रममा तपाईंको घडीमा इन्स्टल गरिएका एपहरूले पनि तपाईंको फोनमा दिइएको जस्तै अनुमति प्रयोग गर्ने छन्।\n\n यी अनुमतिमा तपाईंको घडीको माइक्रोफोन र लोकेसन प्रयोग गर्ने जस्ता अनुमति पर्न सक्छन्।"</string>
+ <string name="consent_back" msgid="2560683030046918882">"पछाडि"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; मा भएका एपहरूलाई पनि &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मा दिइएकै अनुमति दिने हो?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;यसअन्तर्गत &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; का माइक्रोफोन, क्यामेरा र लोकेसन प्रयोग गर्ने अनुमतिका तथा अन्य संवेदनशील अनुमति समावेश हुन्छन्।&lt;/p&gt; &lt;p&gt;तपाईं &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; का सेटिङमा गई जुनसुकै बेला यी अनुमति परिवर्तन गर्न सक्नुहुन्छ।&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"एपको आइकन"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"थप जानकारी देखाउने बटन"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index bc09a58afee1..a3b4cef932f4 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan je &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te beheren"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot je &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; apps streamt?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Deze app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot rechten voor Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"De apps van je telefoon streamen"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot de foto\'s, media en meldingen van je telefoon"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om apps te streamen tussen je apparaten"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
<string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-rechten overzetten naar je horloge"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"We willen het makkelijker voor je maken om je horloge in te stellen. Daarom gebruiken apps die tijdens het instellen worden geïnstalleerd op je horloge, dezelfde rechten als op je telefoon.\n\n Deze rechten kunnen toegang tot de microfoon en locatie van je horloge omvatten."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Terug"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&amp;gt dezelfde rechten geven als op &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dit kan toegang tot de microfoon, camera en je locatie en andere gevoelige rechten op je &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; omvatten.&lt;/p&gt; &lt;p&gt;Je kunt deze rechten op elk moment wijzigen in je Instellingen op de <xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"App-icoon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Knop Meer informatie"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 92d0a5ef5f1d..4fe9d0cba278 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"ଆପଣଙ୍କ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"ଆପଣଙ୍କ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ, କ୍ୟାଲେଣ୍ଡର, କଲ ଲଗ ଏବଂ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ଆପ୍ସ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"ଆପଣଙ୍କ ଫୋନର ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"ଯୋଗାଯୋଗ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ିପାରିବ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ସେବାଗୁଡ଼ିକ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ଆପଣଙ୍କ ୱାଚକୁ ଆପ ଅନୁମତିଗୁଡ଼ିକ ଟ୍ରାନ୍ସଫର କରନ୍ତୁ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ଆପଣଙ୍କ ୱାଚ ସେଟ ଅପ କରିବାକୁ ସହଜ କରିବା ପାଇଁ, ସେଟଅପ ସମୟରେ ଆପଣଙ୍କର ୱାଚରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପଗୁଡ଼ିକ ଆପଣଙ୍କ ଫୋନରେ ଥିବା ଆପଗୁଡ଼ିକ ପରି ସମାନ ଅନୁମତିଗୁଡ଼ିକ ବ୍ୟବହାର କରିବ।\n\n ଏହି ଅନୁମତିଗୁଡ଼ିକରେ ଆପଣଙ୍କ ୱାଚର ମାଇକ୍ରୋଫୋନ ଏବଂ ଲୋକେସନକୁ ଆକ୍ସେସ ଅନ୍ତର୍ଭୁକ୍ତ ହୋଇପାରେ।"</string>
+ <string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ପରି &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;ରେ ଥିବା ଆପ୍ସକୁ ସମାନ ଅନୁମତିଗୁଡ଼ିକ ଦେବେ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ଏହା &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ରେ ମାଇକ୍ରୋଫୋନ, କ୍ୟାମେରା ଏବଂ ଲୋକେସନ ଆକ୍ସେସ ଓ ଅନ୍ୟ ସମ୍ବେଦନଶୀଳ ଅନୁମତିଗୁଡ଼ିକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରିପାରେ।&lt;/p&gt; &lt;p&gt;ଆପଣ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ରେ ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ସେଟିଂସରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ଆପ ଆଇକନ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ଅଧିକ ସୂଚନା ବଟନ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index c28be2543707..5fdcd366ddd3 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;gt ਨੂੰ ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਇਹ ਐਪ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਕੈਲੰਡਰ, ਕਾਲ ਲੌਗਾਂ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ਐਪਾਂ"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"ਤੁਸੀਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹ ਸਕਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ਸੇਵਾਵਾਂ"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
- <string name="consent_yes" msgid="8344487259618762872">"ਇਜਾਜ਼ਤ ਦਿਓ"</string>
- <string name="consent_no" msgid="2640796915611404382">"ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ਐਪ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਆਪਣੀ ਘੜੀ \'ਤੇ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰੋ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ਤੁਹਾਡੀ ਘੜੀ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਆਸਾਨ ਬਣਾਉਣ ਲਈ, ਤੁਹਾਡੀ ਘੜੀ \'ਤੇ ਸਥਾਪਤ ਐਪਾਂ ਸੈੱਟਅੱਪ ਦੌਰਾਨ ਉਹੀ ਇਜਾਜ਼ਤਾਂ ਵਰਤਣਗੀਆਂ ਜੋ ਤੁਹਾਡਾ ਫ਼ੋਨ ਵਰਤਦਾ ਹੈ।\n\n ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਵਿੱਚ ਤੁਹਾਡੀ ਘੜੀ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ।"</string>
+ <string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string>
+ <string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
+ <string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ਕੀ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਵਾਂਗ ਇਜਾਜ਼ਤਾਂ ਦੇਣੀਆਂ ਹਨ?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ਇਸ ਵਿੱਚ ਮਾਈਕ੍ਰੋਫ਼ੋਨ, ਕੈਮਰਾ, ਟਿਕਾਣਾ ਪਹੁੰਚ ਅਤੇ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਹੋਰ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀਆਂ ਹਨ।&lt;/p&gt; &lt;p&gt;ਤੁਸੀਂ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਆਪਣੀਆਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਦੇ ਵੀ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ਐਪ ਪ੍ਰਤੀਕ"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ਹੋਰ ਜਾਣਕਾਰੀ ਬਟਨ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index f9fd206250d9..c890fbc27948 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Zezwól na zarządzanie urządzeniem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Zezwól na dostęp aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie danych z aplikacji?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na telefonie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym telefonem."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na tablecie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym tabletem."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z urządzeniem."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i urządzeń w pobliżu."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące dostępu do zdjęć, multimediów i powiadomień na telefonie"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Może odczytywać wszystkie powiadomienia, w tym informacje takie jak kontakty, wiadomości i zdjęcia"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania aplikacji między urządzeniami"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
<string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Przenieś uprawnienia aplikacji na zegarek"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Aby łatwiej było skonfigurować zegarek, aplikacje zainstalowane na nim podczas konfiguracji będą korzystały z tych samych uprawnień co telefon.\n\n Może to oznaczać dostęp do mikrofonu i lokalizacji na zegarku."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Wstecz"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Czy aplikacjom na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; przyznać te same uprawnienia co na urządzeniu &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Mogą one obejmować dane dostęp do Mikrofonu, Aparatu i lokalizacji oraz inne uprawnienia newralgiczne na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Możesz w dowolnym momencie zmienić uprawnienia na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacji"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Przycisk – więcej informacji"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 161188c70c6c..87986f11b310 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Esse app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Você pode mudar essas permissões a qualquer momento nas configurações do &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 9124a405198a..0584694cc62c 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça a gestão do seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda ao seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream de aplicações?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste tablet quando estiver ligado."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Esta app é necessária para gerir o seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos, Calendário, Registos de chamadas e Dispositivos próximos."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para aceder às fotos, conteúdo multimédia e notificações do seu telemóvel"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfira as autorizações da app para o seu relógio"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do seu relógio, as apps instaladas no mesmo durante a configuração utilizarão as mesmas autorizações que o telemóvel.\n\n Estas autorizações podem incluir o acesso ao microfone e à localização do seu relógio."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Atribuir às apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas autorizações que no dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isto pode incluir o acesso ao microfone, câmara e localização, bem como a outras autorizações confidenciais no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Pode alterar estas autorizações em qualquer altura nas Definições do dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone da app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão Mais informações"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 161188c70c6c..87986f11b310 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Esse app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Você pode mudar essas permissões a qualquer momento nas configurações do &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index da7ae9e0f1bd..449dc86c37fa 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să vă gestioneze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să vă acceseze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
<string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a accesa fotografiile, conținutul media și notificările de pe telefon"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificări"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Poate să citească toate notificările, inclusiv informații cum ar fi agenda, mesajele și fotografiile"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele dvs."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string>
<string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferați permisiunile pentru aplicații pe ceas"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurați mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Oferiți aplicațiilor de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; aceleași permisiuni ca pe &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Aici pot fi incluse accesul la microfon, la camera foto, la locație și alte permisiuni de accesare a informațiilor sensibile de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puteți modifica oricând aceste permisiuni din Setările de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Pictograma aplicației"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Butonul Mai multe informații"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index dbb09c9e7c96..b7f0547d3ec9 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять этим устройством: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ к устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом телефоне."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом планшете."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом устройстве."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" получит доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты, календарь, список вызовов и устройства поблизости."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Трансляция приложений с телефона."</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы получить доступ к фотографиям, медиаконтенту и уведомлениям на телефоне."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает доступ от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы транслировать приложения между вашими устройствами."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
<string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенос разрешений для приложений на часы"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Для приложений, установленных на часы во время настройки, будут использоваться те же разрешения, что и на телефоне.\n\n Например, может быть включен доступ к микрофону на часах или сведениям о местоположении."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Предоставить приложениям на устройстве &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; те же разрешения, что на устройстве &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Сюда может входить доступ к микрофону, камере и данным о местоположении, а также другие разрешения на доступ к конфиденциальной информации на устройстве &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Вы можете в любое время изменить разрешения в настройках устройства &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Значок приложения"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка информации"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index a3de2a393181..48674b781f1b 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට යෙදුම් ප්‍රවාහ කිරීමට ඉඩ දෙන්නද?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"මෙම යෙදුමට ඔබගේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්‍යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, SMS, සම්බන්ධතා, දින දර්ශනය, ඇමතුම් ලොග සහ අවට උපාංග අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"යෙදුම්"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"ඔබගේ දුරකථනයේ යෙදුම් ප්‍රවාහ කරන්න"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ දුරකථනයෙහි ඡායාරූප, මාධ්‍ය සහ දැනුම්දීම් වෙත ප්‍රවේශ වීමට අවසරය ඉල්ලමින් සිටී"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"සම්බන්ධතා, පණිවිඩ සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව සියලු දැනුම්දීම් කියවිය හැකිය"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්‍ය"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play සේවා"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ උපාංග අතර යෙදුම් ප්‍රවාහ කිරීමට අවසරය ඉල්ලමින් සිටී"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
<string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ඔබගේ ඔරලෝසුවට යෙදුම් අවසර මාරු කිරීම"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"ඔබගේ ඔරලෝසුව පිහිටුවීම පහසු කිරීමට, පිහිටුවීමේදී ඔබගේ ඔරලෝසුවේ ස්ථාපනය කර ඇති යෙදුම් ඔබගේ දුරකථනයට සමාන අවසර භාවිත කරනු ඇත.\n\n මෙම අවසරවලට ඔබගේ ඔරලෝසුවේ මයික්‍රෆෝනයට සහ ස්ථානයට ප්‍රවේශය ඇතුළත් විය හැකිය."</string>
+ <string name="consent_back" msgid="2560683030046918882">"ආපසු"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the හි යෙදුම්වලට &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හි අවසරම දෙන්නද?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;මෙයට මයික්‍රෆෝනය, කැමරාව සහ ස්ථාන ප්‍රවේශය සහ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; හි අනෙකුත් සංවේදී අවසර ඇතුළත් විය හැකිය.&lt;/p&gt; &lt;p&gt;ඔබට ඔබගේ සැකසීම් තුළ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; හිදී ඕනෑම වේලාවක මෙම අවසර වෙනස් කළ හැකිය.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"යෙදුම් නිරූපකය"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"වැඩිදුර තොරතුරු බොත්තම"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index dd75ef590913..5c2ce5cd01d5 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovať zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Chcete aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; povoliť streamovanie aplikácií?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k telefónu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k povoleniam telefónu, SMS, kontaktov, kalendára, zoznamu hovorov a zariadení v okolí."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streamovanie aplikácií v telefóne"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na streamovanie aplikácií medzi vašimi zariadeniami v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Presun povolení aplikácie do hodiniek"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"V rámci zjednodušenia nastavenia hodiniek budú aplikácie nainštalované do hodiniek pri nastavovaní používať rovnaké povolenia ako váš telefón.\n\n Tieto povolenia môžu zahrnovať prístup k mikrofónu a polohe hodiniek."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Späť"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Chcete udeliť aplikáciám v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; rovnaké povolenia ako v zariadení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Môžu zahŕňať prístup k mikrofónu, kamere a polohe a ďalšie citlivé povolenia v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Tieto povolenia môžete kedykoľvek zmeniť v Nastaveniach v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikácie"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Tlačidlo Ďalšie informácie"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 7cb5fb58fb60..3b31abc49451 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti pretočno predvajanje aplikacij?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do telefona &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do tabličnega računalnika &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bosta omogočena interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Koledar, Dnevniki klicev in Naprave v bližini."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v telefonu."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu."</string>
+ <string name="title_computer" msgid="4693714143506569253">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij v vaših napravah."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenos dovoljenj za aplikacije v uro"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Za lažjo nastavitev ure bodo aplikacije, ki so bile med nastavljanjem nameščene v uri, uporabljale enaka dovoljenja kot tiste v telefonu.\n\n Ta dovoljenja lahko vključujejo dostop do mikrofona in lokacije ure."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Nazaj"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ali želite aplikacijam v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; odobriti enaka dovoljenja kot v napravi &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To lahko vključuje dostop do mikrofona, fotoaparata in lokacije ter druga občutljiva dovoljenja v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ta dovoljenja lahko kadar koli spremenite v nastavitvah v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb za več informacij"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 62c711abf398..a63eaaa58cd5 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të menaxhojë pajisjen tënde &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje te &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; t\'i ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ky aplikacion nevojitet për të menaxhuar profilin tënd të <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Kalendarit\", \"Evidencave të telefonatave\" dhe \"Pajisjeve në afërsi\"."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Mund të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
<string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfero lejet e aplikacionit te ora jote"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Për ta bërë më të lehtë konfigurimin e orës, aplikacionet e instaluara në orën tënde gjatë konfigurimit do të përdorin të njëjtat leje si telefoni yt.\n\n Këto leje mund të përfshijnë qasje në mikrofonin dhe vendndodhjen e orës."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Pas"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"T\'i jepen aplikacioneve në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; të njëjtat leje si në &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Kjo mund të përfshijë qasjen te \"Mikrofoni\", \"Kamera\", \"Vendndodhja\" dhe leje të tjera për informacione delikate në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&amp;gtTi mund t\'i ndryshosh këto leje në çdo kohë te \"Cilësimet\" në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona e aplikacionit"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Butoni \"Më shumë informacione\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 8d51c62fd3e7..9d39188c7da3 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Желите да дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримује апликације?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на телефону &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на таблету &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, календар, евиденције позива и уређаје у близини."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Апликације"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Стримујте апликације на телефону"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за приступ сликама, медијском садржају и обавештењима са телефона"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Може да чита сва обавештења, укључујући информације попут контаката, порука и слика"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за стримовање апликација између уређаја"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Пренесите дозволе за апликације на сат"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Да бисмо поједноставили подешавање сата, апликације инсталиране на сату током подешавања ће користити исте дозволе као телефон.\n\n Те дозволе могу да обухватају приступ микрофону и локацији сата."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Апликцијама на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дајте све дозволе као на уређају &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;То може да обухвата приступ микрофону, камери и локацији, као и другим осетљивим дозволама на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;У сваком тренутку можете да промените те дозволе у Подешавањима на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Икона апликације"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Дугме за више информација"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index ca1ec8769675..31dd2d8a6c7c 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hanterar din &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får åtkomst till din &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vill du tillåta att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamar appar?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Kalender, Samtalsloggar och Enheter i närheten."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Appar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att ge <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> åtkomst till foton, mediefiler och aviseringar på telefonen"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kan läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att låta <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> streama appar mellan enheter"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Överför appbehörigheter till klockan"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Appar som installeras på klockan under konfigureringen får samma behörigheter som de har på telefonen så att konfigureringen ska bli enklare.\n\n Behörigheterna kan omfatta åtkomst till klockans mikrofon och plats."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vill du ge apparna på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; samma behörigheter som de har på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Det kan gälla behörighet till mikrofon, kamera och plats och åtkomstbehörighet till andra känsliga uppgifter på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan när som helst ändra behörigheterna i inställningarna på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Knappen Mer information"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index cf9260087bd2..e906dc8089ed 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; idhibiti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yako"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yako"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Programu hii inahitajika ili udhibiti wasifu wako wa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa zako za Simu, SMS, Anwani, Kalenda, Rekodi za nambari za simu na Vifaa vilivyo karibu."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programu"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili kufikia picha, maudhui na arifa za simu yako"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Arifa"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Inaweza kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile anwani, ujumbe na picha"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili kutiririsha programu kati ya vifaa vyako"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
<string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Hamishia idhini za programu kwenye saa yako"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Ili kurahisisha kuweka mipangilio ya saa yako, programu ambazo zimesakinishwa kwenye saa yako wakati wa kuweka mipangilio zitatumia ruhusa sawa na zinazotumika kwenye simu yako.\n\n Ruhusa hizi huenda zikajumuisha ufikiaji wa maikrofoni ya saa yako na maelezo ya mahali ilipo saa yako."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Nyuma"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Zipatie programu katika &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ruhusa ile ile kama kwenye &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Hii huenda ikajumuisha ufikiaji wa Maikrofoni, Kamera na Mahali, pamoja na ruhusa nyingine nyeti kwenye &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Unaweza kubadilisha ruhusa hizi muda wowote katika Mipangilio yako kwenye &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Aikoni ya Programu"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Kitufe cha Maelezo Zaidi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index b86ea1cffacf..1cba5e8f7e4f 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"உங்கள் &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ஐ நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"உங்கள் &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ஆப்ஸை ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"உங்கள் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவைப்படுகிறது. உங்கள் அறிவிப்புகளைப் பயன்படுத்துவதற்கான அனுமதியையும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர், அழைப்புப் பதிவுகள், அருகிலுள்ள சாதனங்கள் ஆகியவற்றின் அனுமதிகளுக்கான அணுகலையும் <xliff:g id="APP_NAME">%2$s</xliff:g> ஆப்ஸ் பெறும்."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ஆப்ஸ்"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"உங்கள் மொபைலின் ஆப்ஸை ஸ்ட்ரீம் செய்யலாம்"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவும்"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"பன்முக சாதன சேவைகள்"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"உங்கள் மொபைலில் உள்ள படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை அணுக உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கோருகிறது"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"உங்கள் மொபைலிலிருந்து இந்தத் தகவலை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play சேவைகள்"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கோருகிறது"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
<string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ஆப்ஸ் அனுமதிகளை உங்கள் வாட்ச்சிற்கு மாற்றுதல்"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"உங்கள் வாட்ச் அமைவை எளிதாக்க, உங்கள் மொபைலில் வழங்கியுள்ள அனுமதிகளையே அமைவின்போது வாட்ச்சில் நிறுவப்பட்ட ஆப்ஸும் பயன்படுத்தும்.\n\n உங்கள் வாட்ச்சிலுள்ள மைக்ரோஃபோன், இருப்பிடம் ஆகியவற்றுக்கான அணுகலும் இந்த அனுமதிகளில் அடங்கக்கூடும்."</string>
+ <string name="consent_back" msgid="2560683030046918882">"பின்செல்"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தில் இருக்கும் அதே அனுமதிகளை &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; சாதனத்தில் உள்ள ஆப்ஸுக்கும் வழங்கவா?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; சாதனத்தில் உள்ள மைக்ரோஃபோன், கேமரா, இருப்பிட அணுகல், பாதுகாக்கவேண்டிய பிற தகவல்கள் ஆகியவற்றுக்கான அனுமதிகள் இதிலடங்கும்.&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; சாதனத்தில் உள்ள அமைப்புகளில் இந்த அனுமதிகளை எப்போது வேண்டுமானாலும் நீங்கள் மாற்றிக்கொள்ளலாம்."</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ஆப்ஸ் ஐகான்"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"கூடுதல் தகவல்கள் பட்டன்"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 73cf3e88e180..96e760832d64 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"మీ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ను మేనేజ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"మీ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"యాప్‌లను స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించాలా?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి అలాగే మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar కాల్ లాగ్‌లు, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"యాప్‌లు"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"మీ ఫోన్ యాప్‌లను స్ట్రీమ్ చేయండి"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> మీ ఫోన్ ఫోటోలు, మీడియా, నోటిఫికేషన్‌లను యాక్సెస్ చేయడానికి మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరపున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్‌లు"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"కాంటాక్ట్‌లు, మెసేజ్‌లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్‌లను చదవగలరు"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"మీ పరికరాల మధ్య యాప్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరపున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"అనుమతించు"</string>
<string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"మీ వాచ్‌కు యాప్ అనుమతులను బదిలీ చేయండి"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"మీ వాచ్‌ను సెటప్ చేయడాన్ని సులభతరం చేయడానికి, సెటప్ సమయంలో మీ వాచ్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లు మీ ఫోన్‌లో యాప్‌లకు ఉన్న అవే అనుమతులను ఉపయోగిస్తాయి.\n\n ఈ అనుమతులతో మీ వాచ్ మైక్రోఫోన్, అలాగే లొకేషన్ కూడా ఉండవచ్చు."</string>
+ <string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;లోని యాప్‌లకు &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;లో ఉన్న అనుమతులను ఇవ్వాలా?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;లో మైక్రోఫోన్, కెమెరా, లొకేషన్ యాక్సెస్, ఇంకా ఇతర గోప్యమైన సమాచార యాక్సెస్ అనుమతులు ఇందులో ఉండవచ్చు.&lt;/p&gt; &lt;p&gt;మీరు &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;లో మీ సెట్టింగ్‌లలో ఎప్పుడైనా ఈ అనుమతులను మార్చవచ్చు.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"యాప్ చిహ్నం"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"మరింత సమాచారం బటన్"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 6f29346debc5..d5ba74a8fbba 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; จัดการ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ของคุณ"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ของคุณ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
<string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปพลิเคชันใช่ไหม"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ปฏิทิน, บันทึกการโทร และอุปกรณ์ที่อยู่ใกล้เคียง"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"แอป"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"สตรีมแอปของโทรศัพท์คุณ"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อเข้าถึงรูปภาพ สื่อ และการแจ้งเตือนในโทรศัพท์ของคุณ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
<string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"โอนสิทธิ์ของแอปไปยังนาฬิกา"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"แอปที่ติดตั้งในนาฬิการะหว่างการตั้งค่าจะใช้สิทธิ์เดียวกันกับโทรศัพท์เพื่อให้การตั้งค่านาฬิกาง่ายขึ้น\n\n สิทธิ์เหล่านี้อาจรวมการเข้าถึงไมโครโฟนและตำแหน่งของนาฬิกา"</string>
+ <string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ให้แอปใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; มีสิทธิ์เหมือนกับใน &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ไหม"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;โดยอาจรวมถึงสิทธิ์เข้าถึงไมโครโฟน กล้อง และตำแหน่ง ตลอดจนสิทธิ์ที่มีความละเอียดอ่อนอื่นๆ ใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;คุณเปลี่ยนแปลงสิทธิ์เหล่านี้ได้ทุกเมื่อในการตั้งค่าใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ไอคอนแอป"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"ปุ่มข้อมูลเพิ่มเติม"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index e557a385dd98..6376863649ce 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na pamahalaan ang iyong &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang iyong &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na mag-stream ng mga application?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Kailangan ang app na ito para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga notification mo at i-access ang iyong pahintulot sa Telepono, SMS, Mga Contact, Kalendaryo, Log ng mga tawag, at Mga kalapit na device."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Mga App"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyong ito sa iyong telepono"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para i-access ang mga larawan, media, at notification ng telepono mo"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyon sa iyong telepono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Magbasa ng lahat ng notification, kabilang ang impormasyon gaya ng mga contact, mensahe, at larawan"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para mag-stream ng mga app sa pagitan ng mga device mo"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
<string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilipat sa iyong relo ang mga pahintulot sa app"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Para gawing mas madali na i-set up ang iyong relo, gagamitin ng mga app na naka-install sa relo mo sa oras ng pag-set up ang mga pahintulot na ginagamit din sa iyong telepono.\n\n Posibleng kasama sa mga pahintulot na ito ang access sa mikropono at lokasyon ng iyong relo."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Bumalik"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Bigyan ang mga app sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ng mga pahintulot na mayroon din sa &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Posibleng kabilang dito ang access sa Mikropono, Camera, at Lokasyon, at iba pang pahintulot sa sensitibong impormasyon sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puwede mong baguhin ang mga pahintulot na ito anumang oras sa iyong Mga Setting sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Icon ng App"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Button ng Dagdag Impormasyon"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index c75214bf957e..bba7922582a1 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulaması &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı yönetebilsin mi?"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınıza erişmesi için &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasına izin verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, uygulamalarda akış gerçekleştirmesine izin verilsin mi?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Takvim, Arama kayıtları ve Yakındaki cihazlar izinlerinize erişmesine izin verilir."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını yayınlama"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuyabilir"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akışı gerçekleştirmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
<string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Uygulama izinlerini saatinize aktarma"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Kurulum sırasında saatinize yüklenen uygulamalar, saat kurulumunuzu kolaylaştırmak için telefonunuzla aynı izinleri kullanır.\n\n Saatinizin mikrofonuna ve konumuna erişim bu izinlere dahil olabilir."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Geri"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındaki uygulamalara, &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakiyle aynı izinler verilsin mi?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Mikrofon, Kamera ve Konum erişiminin yanı sıra &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; cihazındaki diğer hassas bilgilere erişim izinleri de bu kapsamda olabilir.&lt;/p&gt; &lt;p&gt;Bu izinleri istediğiniz zaman &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; cihazındaki Ayarlar bölümünden değiştirebilirsiniz.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Uygulama Simgesi"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Daha Fazla Bilgi Düğmesi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 46a25b2ba185..718fad35580f 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; керувати вашим пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Надати додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслювати інші додатки?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому телефоні."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому планшеті."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому пристрої."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Цей додаток потрібен, щоб керувати пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Календар\", \"Журнали викликів\" і \"Пристрої поблизу\"."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Додатки"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Транслювати додатки телефона"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на доступ до фотографій, медіафайлів і сповіщень вашого телефона"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
- <string name="title_computer" msgid="4693714143506569253">"Надайте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
+ <string name="title_computer" msgid="4693714143506569253">"Надайте пристрою &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Сервіси Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на трансляцію додатків між вашими пристроями"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенести дозволи для додатків на годинник"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Задля зручності додатки, установлені на годиннику протягом налаштування, використовуватимуть ті самі дозволи, що й на телефоні.\n\n До таких дозволів може належати доступ до мікрофона й геоданих годинника."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Надати додаткам на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; такі самі дозволи, що й на пристрої &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Це може бути доступ до мікрофона, камери та геоданих, а також до іншої конфіденційної інформації на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ви можете будь-коли змінити ці дозволи в налаштуваннях на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Значок додатка"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка \"Докладніше\""</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index c9f930f0f54b..ef93add2e454 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"‏اپنے &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; کا نظم کرنے کے لیے ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو اجازت دیں"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو اپنے ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎ تک رسائی کی اجازت دیں"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="chooser_title" msgid="2262294130493605839">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو ایپلیکیشنز کی سلسلہ بندی کرنے کی اجازت دیں؟"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"‏آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لئے اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں، کیلنڈر، کال لاگز اور قریبی آلات کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ایپس"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی اجازت دیں"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ڈیوائس سروسز"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے فون کی تصاویر، میڈیا اور اطلاعات تک رسائی کی اجازت طلب کر رہی ہے"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"‏اپنے فون سے اس معلومات تک رسائی حاصل Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کرنے کی اجازت دیں"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"رابطوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھ سکتے ہیں"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"‏Google Play سروسز"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string>
<string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"اپنی گھڑی پر ایپ کی اجازتیں منتقل کریں"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"آپ کی گھڑی کو سیٹ اپ کرنے کے عمل کو زیادہ آسان بنانے کے لیے، سیٹ اپ کے دوران آپ کی گھڑی پر انسٹال کردہ ایپس انہیں اجازتوں کا استعمال کریں گی جن کا استعمال آپ کا فون کرتا ہے۔\n\n ان اجازتوں میں آپ کی گھڑی کے مائیکروفون اور مقام تک کی رسائی شامل ہو سکتی ہے۔"</string>
+ <string name="consent_back" msgid="2560683030046918882">"پیچھے"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏ایپس کو ;‎&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&amp;gt پر اجازت دیں یکساں اجازتیں جو ‎&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>;&lt;/strong&amp;gt پر کے بطور ہیں؟"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;اس میں مائیکروفون، کیمرا اور مقام تک رسائی اور ;‎&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&amp;gt پر دیگر حساس اجازتیں شامل ہو سکتی ہیں۔&lt;/p&gt; &lt;p&gt;آپ ‎&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>;&lt;/strong&amp;gt پر کسی بھی وقت اپنی ترتیبات میں ان اجازتوں کو تبدیل کر سکتے ہیں۔&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"ایپ کا آئیکن"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"مزید معلومات کا بٹن"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 91fdd946edf2..1813857d3166 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasini boshqarish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ruxsat bering"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasiga kirish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ruxsat bering"</string>
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ilovalarni strim qilishi uchun ruxsat berilsinmi?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, taqvim, chaqiruvlar jurnali va yaqin-atrofdagi qurilmalarga kirishga ruxsat beriladi."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Telefoningizdagi rasm, media va bildirishnomalarga kirish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Qurilamalararo ilovalar strimingi uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilova uchun ruxsatlarni soatingizga uzating"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Soatingizni sozlashni qulaylashtirish maqsadida sozlash paytida soatingizga oʻrnatilgan ilovalar telefoningiz bilan bir xil ruxsatlardan foydalanadi.\n\n Bunday ruxsatlarga soatingiz mikrofoni va joylashuv axborotiga ruxsatlar kirishi mumkin."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Orqaga"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovalariga &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasidagi kabi bir xil ruxsatlar berilsinmi?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Bunga &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; qurilmasidagi Mikrofon, Kamera, Joylashuv kabi muhim ruxsatlar kirishi mumkin.&lt;/p&gt; &lt;p&gt;Bu ruxsatlarni istalgan vaqt &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; Sozlamalari orqali oʻzgartirish mumkin.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Ilova belgisi"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Batafsil axborot tugmasi"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 4f96bd4d7f1a..045547b0e61b 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; quản lý &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến ứng dụng?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi điện thoại này có kết nối."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi máy tính bảng này có kết nối."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi thiết bị này có kết nối."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"Cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> sẽ được phép tương tác với các thông báo và truy cập vào Điện thoại, SMS, Danh bạ, Lịch, Nhật ký cuộc gọi và quyền đối với Thiết bị ở gần."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truy cập vào ảnh, nội dung nghe nhìn và thông báo trên điện thoại của bạn."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Có thể đọc tất cả các thông báo, kể cả những thông tin như danh bạ, tin nhắn và ảnh"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truyền trực tuyến ứng dụng giữa các thiết bị của bạn"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
<string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Chuyển quyền cho ứng dụng sang đồng hồ"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Để thiết lập đồng hồ dễ dàng hơn, trong quá trình thiết lập, các ứng dụng được cài đặt trên đồng hồ của bạn sẽ sử dụng các quyền giống như trên điện thoại.\n\n Các quyền này có thể bao gồm quyền sử dụng micrô và thông tin vị trí của đồng hồ."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Quay lại"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Cấp cho các ứng dụng trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; các quyền giống như trên &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Những quyền này có thể bao gồm quyền truy cập vào micrô, máy ảnh và thông tin vị trí, cũng như các quyền truy cập thông tin nhạy cảm khác trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Bạn có thể thay đổi những quyền này bất cứ lúc nào trong phần Cài đặt trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Biểu tượng ứng dụng"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Nút thông tin khác"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 3fdccf229bf8..06a8b3eaab81 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;访问您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
<string name="chooser_title" msgid="2262294130493605839">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"是否允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 流式传输应用?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该手机上安装的应用。"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该平板电脑上安装的应用。"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该设备上安装的应用。"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"需要使用此应用,才能管理您的“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”。“<xliff:g id="APP_NAME">%2$s</xliff:g>”将能与通知互动,并可获得电话、短信、通讯录、日历、通话记录和附近的设备访问权限。"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"应用"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机上的应用"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”&lt;strong&gt;&lt;/strong&gt;访问您手机中的这项信息"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求访问您手机上的照片、媒体内容和通知"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 访问您手机中的这项信息"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"可以读取所有通知,包括合同、消息和照片等信息"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求在您的设备之间流式传输应用内容"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"允许"</string>
<string name="consent_no" msgid="2640796915611404382">"不允许"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"将应用权限转让给手表"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"为了让您更轻松地设置手表,在设置过程中安装在手表上的应用将使用与手机相同的权限。\n\n这些权限可能包括使用手表的麦克风和位置信息。"</string>
+ <string name="consent_back" msgid="2560683030046918882">"返回"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要授予&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;上的应用与&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;上相同的权限吗?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;这可能包括&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;的麦克风、摄像头和位置信息访问权限,以及其他敏感权限。&lt;/p&gt; &lt;p&gt;您可以随时在&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;的“设置”中更改这些权限。&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"应用图标"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"更多信息按钮"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index a4dc0c9b6c81..6956affe9092 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允許 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 管理您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"允許&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 存取您的 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"必須使用此應用程式,才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。<xliff:g id="APP_NAME">%2$s</xliff:g> 將可存取通知、電話、短訊、通訊錄和日曆、通話記錄和附近的裝置權限。"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求必要權限,以便存取手機上的相片、媒體和通知"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求必要權限,以便在裝置之間串流應用程式內容"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"允許"</string>
<string name="consent_no" msgid="2640796915611404382">"不允許"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移至手錶"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,在設定過程中安裝到手錶上的應用程式都將沿用手機上的權限。\n\n這些權限可能包括手錶麥克風和位置的存取權。"</string>
+ <string name="consent_back" msgid="2560683030046918882">"返回"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; 的應用程式沿用在 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 上的權限嗎?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;這可能包括 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; 的麥克風、相機和位置存取權和其他敏感資料權限。您隨時可透過 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; 變更這些權限。"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"「更多資料」按鈕"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index eec042429ca8..8d4623a7c676 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理員"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理你的「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string>
+ <string name="summary_watch" msgid="3002344206574997652">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆、通話記錄和鄰近裝置的權限。"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取手機中的這項資訊"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便存取手機上的相片、媒體和通知"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取你手機中的這項資訊"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"可讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便在裝置之間串流傳輸應用程式內容"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"允許"</string>
<string name="consent_no" msgid="2640796915611404382">"不允許"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移到手錶上"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,只要是在設定過程中安裝到手錶上的應用程式,都將沿用手機上的權限。\n\n 這些權限可能包括手錶的麥克風和位置資訊存取權。"</string>
+ <string name="consent_back" msgid="2560683030046918882">"返回"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓「<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;的應用程式沿用在「<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;上的權限嗎?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;這可能包括「<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;.&lt;/p&gt;的麥克風、相機和位置資訊存取權和其他機密權限。&lt;/p&gt; &lt;p&gt;你隨時可透過「<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;的設定變更這些權限。&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"更多資訊按鈕"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index be5a195fa5f7..c6697367c5fe 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -17,23 +17,32 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi iphathe i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yakho"</string>
+ <string name="confirmation_title" msgid="3785000297483688997">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi ifinyelele i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yakho"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
- <string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukusakaza ama-applications?"</string>
- <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string>
- <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string>
- <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string>
+ <string name="summary_watch" msgid="3002344206574997652">"I-app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele Ifoni yakho, i-SMS, Oxhumana nabo, Ikhalenda, Amarekhodi wamakholi Nezimvume zamadivayisi aseduze."</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifinyelele lolu lwazi kusukela efonini yakho"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze ifinyelele izithombe zefoni yakho, imidiya nezaziso"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukufinyelela lolu lwazi kusuka efonini yakho"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string>
+ <string name="permission_notification_summary" msgid="884075314530071011">"Ingafunda zonke izaziso, okubandakanya ulwazi olufana noxhumana nabo, imilayezo, nezithombe"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string>
+ <string name="helper_summary_computer" msgid="1676407599909474428">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
<string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
- <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dlulisela izimvume ze-app ewashini lakho"</string>
- <string name="permission_sync_summary" msgid="8873391306499120778">"Ukuze wenze kube lula ukusetha iwashi lakho, ama-app afakwe ewashini lakho phakathi nokusetha azosebenzisa izimvume ezifanayo nezefoni yakho.\n\n Lezi zimvume zingabandakanya ukufinyelela kumakrofoni nendawo yewashi lakho."</string>
+ <string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Nikeza ama-app &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izimvume ezifanayot &lt;strong&gt;njengaku-<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Lokhu kungase kuhlanganisa Imakrofoni, Ikhamera, kanye Nokufinyelela kwendawo, kanye nezinye izimvume ezibucayi &lt;strong&gt;ku-<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ungashintsha lezi zimvume nganoma yisiphi isikhathi Kumasethingi akho &lt;strong&gt;ku-<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
+ <string name="vendor_icon_description" msgid="4445875290032225965">"Isithonjana Se-app"</string>
+ <string name="vendor_header_button_description" msgid="6566660389500630608">"Inkinobho Yolwazi Olwengeziwe"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index a389bfc42725..cea9a68c57ac 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -104,14 +104,12 @@
<string name="consent_back">Back</string>
<!-- ================== System data transfer ==================== -->
- <!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=60] -->
- <string name="permission_sync_confirmation_title">Transfer app permissions to your
- watch</string>
-
- <!-- Text of the permission sync explanation in the confirmation dialog. [CHAR LIMIT=400] -->
- <string name="permission_sync_summary">To make it easier to set up your watch,
- apps installed on your watch during setup will use the same permissions as your phone.\n\n
- These permissions may include access to your watch\u2019s microphone and location.</string>
+ <!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="permission_sync_confirmation_title">Give apps on &lt;strong&gt;<xliff:g id="companion_device_name" example="Galaxy Watch 5">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="primary_device_name" example="Pixel 6">%2$s</xliff:g>&lt;/strong&gt;?</string>
+
+ <!-- Text of the permission sync explanation in the confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="permission_sync_summary">&lt;p&gt;This may include Microphone, Camera, and Location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="companion_device_name" example="Galaxy Watch 5">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;
+ &lt;p&gt;You can change these permissions any time in your Settings on &lt;strong&gt;<xliff:g id="companion_device_name" example="Galaxy Watch 5">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;</string>
<!--Description for vendor icon [CHAR LIMIT=30]-->
<string name="vendor_icon_description">App Icon</string>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 428f2dc2eb35..2000d9675ca4 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -49,7 +49,6 @@
<style name="DescriptionSummary">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:gravity">center</item>
<item name="android:layout_marginTop">18dp</item>
<item name="android:layout_marginLeft">18dp</item>
<item name="android:layout_marginRight">18dp</item>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index a3aa0100870a..10d46d6db454 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -308,6 +308,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
final MacAddress macAddress = selectedDevice.getMacAddress();
+ mRequest.setDisplayName(selectedDevice.getDisplayName());
onAssociationApproved(macAddress);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
index 67efa03b645f..93040b58d74b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
@@ -16,20 +16,22 @@
package com.android.companiondevicemanager;
+import static android.companion.datatransfer.SystemDataTransferRequest.DATA_TYPE_PERMISSION_SYNC;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+
import static java.util.Objects.requireNonNull;
import android.app.Activity;
-import android.companion.SystemDataTransferRequest;
+import android.companion.datatransfer.PermissionSyncRequest;
+import android.companion.datatransfer.SystemDataTransferRequest;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.os.ResultReceiver;
-import android.text.Html;
import android.util.Log;
-import android.view.View;
import android.widget.Button;
-import android.widget.ListView;
import android.widget.TextView;
/**
@@ -39,14 +41,18 @@ public class CompanionDeviceDataTransferActivity extends Activity {
private static final String LOG_TAG = CompanionDeviceDataTransferActivity.class.getSimpleName();
- // UI -> SystemDataTransferProcessor
- private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED = 0;
- private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_DISALLOWED = 1;
- private static final String EXTRA_SYSTEM_DATA_TRANSFER_REQUEST = "system_data_transfer_request";
+ // Intent data keys from SystemDataTransferProcessor
+ private static final String EXTRA_PERMISSION_SYNC_REQUEST = "permission_sync_request";
+ private static final String EXTRA_COMPANION_DEVICE_NAME = "companion_device_name";
private static final String EXTRA_SYSTEM_DATA_TRANSFER_RESULT_RECEIVER =
"system_data_transfer_result_receiver";
+ // Intent data keys to SystemDataTransferProcessor
+ private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED = 0;
+ private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_DISALLOWED = 1;
+
private SystemDataTransferRequest mRequest;
+ private CharSequence mCompanionDeviceName;
private ResultReceiver mCdmServiceReceiver;
@Override
@@ -61,23 +67,27 @@ public class CompanionDeviceDataTransferActivity extends Activity {
TextView titleView = findViewById(R.id.title);
TextView summaryView = findViewById(R.id.summary);
- ListView listView = findViewById(R.id.device_list);
- listView.setVisibility(View.GONE);
Button allowButton = findViewById(R.id.btn_positive);
Button disallowButton = findViewById(R.id.btn_negative);
final Intent intent = getIntent();
- mRequest = intent.getParcelableExtra(EXTRA_SYSTEM_DATA_TRANSFER_REQUEST);
- mCdmServiceReceiver = intent.getParcelableExtra(EXTRA_SYSTEM_DATA_TRANSFER_RESULT_RECEIVER);
+ mRequest = intent.getParcelableExtra(EXTRA_PERMISSION_SYNC_REQUEST,
+ PermissionSyncRequest.class);
+ mCompanionDeviceName = intent.getCharSequenceExtra(EXTRA_COMPANION_DEVICE_NAME);
+ mCdmServiceReceiver = intent.getParcelableExtra(EXTRA_SYSTEM_DATA_TRANSFER_RESULT_RECEIVER,
+ ResultReceiver.class);
requireNonNull(mRequest);
requireNonNull(mCdmServiceReceiver);
- if (mRequest.isPermissionSyncAllPackages()
- || !mRequest.getPermissionSyncPackages().isEmpty()) {
- titleView.setText(Html.fromHtml(getString(
- R.string.permission_sync_confirmation_title), 0));
- summaryView.setText(getString(R.string.permission_sync_summary));
+ final String primaryDeviceName = Build.MODEL;
+
+ if (mRequest.getDataType() == DATA_TYPE_PERMISSION_SYNC) {
+ titleView.setText(getHtmlFromResources(this,
+ R.string.permission_sync_confirmation_title, mCompanionDeviceName,
+ primaryDeviceName));
+ summaryView.setText(getHtmlFromResources(this, R.string.permission_sync_summary,
+ mCompanionDeviceName));
allowButton.setOnClickListener(v -> allow());
disallowButton.setOnClickListener(v -> disallow());
}
@@ -101,7 +111,9 @@ public class CompanionDeviceDataTransferActivity extends Activity {
private void sendDataToReceiver(int cdmResultCode) {
Bundle data = new Bundle();
- data.putParcelable(EXTRA_SYSTEM_DATA_TRANSFER_REQUEST, mRequest);
+ if (mRequest instanceof PermissionSyncRequest) {
+ data.putParcelable(EXTRA_PERMISSION_SYNC_REQUEST, (PermissionSyncRequest) mRequest);
+ }
mCdmServiceReceiver.send(cdmResultCode, data);
}
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index 4a07d49fcde5..9b0e04444d50 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/Android.bp
@@ -20,4 +20,9 @@ android_library {
sdk_version: "system_current",
min_sdk_version: "28",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ "com.android.adservices",
+ ],
}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 9a80b0267976..87e61b527477 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -50,6 +50,7 @@ android_library {
"SettingsLibTwoTargetPreference",
"SettingsLibSettingsTransition",
"SettingsLibButtonPreference",
+ "SettingsLibDeviceStateRotationLock",
"setupdesign",
"zxing-core-1.7",
],
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index 1817a77981a9..122f60672b2a 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -20,4 +20,8 @@ android_library {
],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
index d7876261ebdd..816cbf67c6a6 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignorar"</string>
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Pechar"</string>
</resources>
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
index 4f6537334770..5c5da9827e61 100644
--- a/packages/SettingsLib/BarChartPreference/Android.bp
+++ b/packages/SettingsLib/BarChartPreference/Android.bp
@@ -19,4 +19,8 @@ android_library {
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/DeviceStateRotationLock/Android.bp b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
new file mode 100644
index 000000000000..c642bd14ed79
--- /dev/null
+++ b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
@@ -0,0 +1,16 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibDeviceStateRotationLock",
+
+ srcs: ["src/**/*.java"],
+
+ min_sdk_version: "21",
+}
diff --git a/packages/SystemUI/res/layout/auth_biometric_view.xml b/packages/SettingsLib/DeviceStateRotationLock/AndroidManifest.xml
index ee4da25f2284..bce6599721e3 100644
--- a/packages/SystemUI/res/layout/auth_biometric_view.xml
+++ b/packages/SettingsLib/DeviceStateRotationLock/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -14,13 +15,7 @@
~ limitations under the License.
-->
-<com.android.systemui.biometrics.AuthBiometricView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.devicestate">
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricView> \ No newline at end of file
+</manifest>
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/AndroidSecureSettings.java
index 8aee576c3d04..8aee576c3d04 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/AndroidSecureSettings.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
index 4ed7e19f341d..4ed7e19f341d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/SecureSettings.java
index 10528739b2b0..10528739b2b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/SecureSettings.java
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 5826047b9f52..aea51b1bba2d 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -19,4 +19,8 @@ android_library {
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp
index 8a4e53d80a7c..aaffdc922875 100644
--- a/packages/SettingsLib/LayoutPreference/Android.bp
+++ b/packages/SettingsLib/LayoutPreference/Android.bp
@@ -14,9 +14,13 @@ android_library {
resource_dirs: ["res"],
static_libs: [
- "androidx.preference_preference",
+ "androidx.preference_preference",
],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
index b5bc8f77045b..fb3c4e6efd90 100644
--- a/packages/SettingsLib/ProgressBar/Android.bp
+++ b/packages/SettingsLib/ProgressBar/Android.bp
@@ -15,4 +15,8 @@ android_library {
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index ef548b59323e..6a8fef36a969 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp
@@ -25,4 +25,8 @@ android_library {
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp
index b7367b4a10a7..5aaee2afc069 100644
--- a/packages/SettingsLib/SearchWidget/Android.bp
+++ b/packages/SettingsLib/SearchWidget/Android.bp
@@ -14,4 +14,8 @@ android_library {
resource_dirs: ["res"],
sdk_version: "system_current",
min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 73459c277df1..1f69c8559d17 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -13,13 +13,15 @@ android_library {
resource_dirs: ["res"],
static_libs: [
- "androidx.preference_preference",
- ],
+ "androidx.preference_preference",
+ ],
sdk_version: "system_current",
min_sdk_version: "21",
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.permission",
+ "com.android.adservices",
],
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1992c9bb7dbf..861f8e75a081 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Stel terug"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Verwyder"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Stel tans gassessie terug …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Stel gastesessie terug?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Dit sal ’n nuwe gastesessie begin en alle programme en data van die huidige sessie uitvee"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Verlaat gasmodus?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Dit sal programme en data in die huidige gastesessie uitvee"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Gaan uit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Stoor gasaktiwiteit?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Jy kan aktiwiteit in die huidige sessie stoor of alle programme en data uitvee"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Vee uit"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Stoor"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Verlaat gasmodus"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Stel jou gastesessie terug"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Verlaat gasmodus"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Alle aktiwiteit sal uitgevee word wanneer jy uitgaan"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Jy kan jou aktiwiteit stoor of uitvee wanneer jy uitgaan"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Stel terug om aktiwiteit nou uit te vee, of stoor of vee aktiwiteit uit wanneer jy uitgaan"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Kies foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Saai <xliff:g id="SWITCHAPP">%1$s</xliff:g> uit"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Verander uitvoer"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Voorspellingteruggebaaranimasies"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktiveer stelselanimasies vir voorspellingteruggebaar."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Hierdie instelling aktiveer stelselanimasies vir voorspellinggebaaranimasie. Dit vereis dat enableOnBackInvokedCallback per program op waar gestel word in die manifeslêer."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index b5982ae533dd..daf4caaede67 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ዳግም አስጀምር"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"አስወግድ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"እንግዳን ዳግም በማስጀመር ላይ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"የእንግዳ ክፍለ-ጊዜ ዳግም ይጀመር?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ይህ አዲስ የእንግዳ ክፍለ-ጊዜ ይጀምራል እና ሁሉንም መተግበሪያዎች እና ውሂብ አሁን ካለው ክፍለ-ጊዜ ይሰርዛል"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ከእንግዳ ሁኔታ ይውጣ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ይህ አሁን ካለው የእንግዳ ክፍለ-ጊዜ መተግበሪያዎችን እና ውሂብን ይሰርዛል"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ውጣ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"የእንግዳ እንቅስቃሴ ይቀመጥ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"እንቅስቃሴን አሁን ካለው ክፍለ-ጊዜ ማስቀመጥ ወይም ሁሉንም መተግበሪያዎች እና ውሂብ መሰረዝ ይችላሉ"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ሰርዝ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"አስቀምጥ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ከእንግዳ ሁኔታ ውጣ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"የእንግዳ ክፍለ-ጊዜን ዳግም አስጀምር"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"እንግዳ ያስወጡ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"በሚወጡበት ጊዜ ሁሉም እንቅስቃሴዎች ይሰረዛሉ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"በሚወጡበት ጊዜ እንቅስቃሴዎን ማስቀመጥ ወይም መሰረዝ ይችላሉ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"የክፍለ-ጊዜ እንቅስቃሴን አሁን ለመሰረዝ ዳግም ያስጀምሩ፣ ወይም በሚወጡበት ጊዜ እንቅስቃሴን ማስቀመጥ ወይም መሰረዝ ይችላሉ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ፎቶ ይምረጡ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>ን ካሰራጩ ወይም ውፅዓትን ከቀየሩ የአሁኑ ስርጭትዎ ይቆማል"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ያሰራጩ"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ውፅዓትን ይቀይሩ"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"የግምት ጀርባ እነማዎች"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ለግምት ጀርባ የስርዓት እንማዎችን ያንቁ።"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ይህ ቅንብር የስርዓት እነማዎችን ለመገመት የምልክት እነማን ያነቃል። በዝርዝር ሰነድ ፋይሉ ውስጥ በእያንዳንዱ መተግበሪያ enableOnBackInvokedCallbackን ወደ እውነት ማቀናበር ያስፈልገዋል።"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index cef5d438a863..55532f7c02fe 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"إعادة الضبط"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"إزالة"</string>
<string name="guest_resetting" msgid="7822120170191509566">"جارٍ إعادة ضبط جلسة الضيف…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"هل تريد إعادة ضبط جلسة الضيف؟"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"سيؤدي إجراء إعادة الضبط إلى بدء جلسة ضيف جديدة وحذف جميع التطبيقات والبيانات من الجلسة الحالية."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"هل تريد الخروج من وضع الضيف؟"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"سيؤدي الخروج من وضع الضيف إلى حذف التطبيقات والبيانات من جلسة الضيف الحالية."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"خروج"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"هل تريد حفظ النشاط في وضع الضيف؟"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"يمكنك حفظ نشاط من الجلسة الحالية أو حذف كلّ التطبيقات والبيانات."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"حذف"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"حِفظ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"الخروج من وضع الضيف"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"إعادة ضبط جلسة الضيف"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"الخروج من وضع الضيف"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"سيتم حذف جميع الأنشطة عند الخروج من وضع الضيف."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"يمكنك حفظ نشاطك أو حذفه عند الخروج من وضع الضيف."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"يمكنك إجراء إعادة ضبط لحذف نشاط الجلسة الآن، أو حِفظ النشاط أو حذفه عند الخروج من وضع الضيف."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"التقاط صورة"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"اختيار صورة"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"اختيار صورة"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"تغيير جهاز الإخراج"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"صور متحركة تعرض إيماءة الرجوع إلى الخلف التنبؤية"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"فعِّل الصور المتحركة في النظام لإيماءة الرجوع إلى الخلف التنبؤية."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏يفعّل هذا الإعداد الصور المتحركة في النظام للصور المتحركة التي تعرض إيماءة الرجوع إلى الخلف التنبؤية. يتطلب الإعداد ضبط enableOnBackInvokedCallback إلى true لكل تطبيق في ملف البيان."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 89cf67eee145..76985a772939 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ৰিছেট কৰক"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"আঁতৰাওক"</string>
<string name="guest_resetting" msgid="7822120170191509566">"অতিথিৰ ছেশ্বন ৰিছেট কৰি থকা হৈছে…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"অতিথিৰ ছেশ্বন ৰিছেট কৰিবনে?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"এইটোৱে এটা অতিথিৰ ছেশ্বন আৰম্ভ কৰিব আৰু বৰ্তমানৰ ছেশ্বনটোৰ পৰা আটাইবোৰ এপ্ আৰু ডেটা মচিব"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"অতিথি ম’ডৰ পৰা বাহিৰ হ’বনে?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"এইটোৱে বৰ্তমানৰ অতিথিৰ ছেশ্বনটোৰ পৰা এপ্ আৰু ডেটা মচিব"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"বাহিৰ হওক"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"অতিথিৰ কাৰ্যকলাপ ছেভ কৰিবনে?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"আপুনি বৰ্তমানৰ ছেশ্বনটোৰ পৰা কাৰ্যকলাপ ছেভ কৰিব পাৰে অথবা আটাইবোৰ এপ্ আৰু ডেটা মচিব পাৰে"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"মচক"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ছেভ কৰক"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"অতিথি ম’ডৰ পৰা বাহিৰ হওক"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"অতিথিৰ ছেশ্বন ৰিছেট কৰক"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"অতিথিৰ ছেশ্বনৰ পৰা বাহিৰ হওক"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"বাহিৰ হওঁতে আটাইবোৰ কাৰ্যকলাপ মচা হ’ব"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"আপুনি বাহিৰ হওঁতে নিজৰ কাৰ্যকলাপ ছেভ কৰিব অথবা মচিব পাৰে"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"এতিয়াই ছেশ্বনৰ কাৰ্যকলাপ ৰিছেট কৰক অথবা মচক অথবা আপুনি বাহিৰ হওঁতে কাৰ্যকলাপ ছেভ কৰিব অথবা মচিব পাৰে"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ফট’ বাছনি কৰক"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্ৰচাৰ কৰক"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"আউটপুট সলনি কৰক"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"প্ৰেডিক্টিভ বেক এনিমেশ্বন"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"প্ৰেডিক্টিভ বেকৰ বাবে ছিষ্টেম এনিমেশ্বন সক্ষম কৰক।"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"এই ছেটিংটোৱে প্ৰেডিক্টিভ বেক এনিমেশ্বনৰ বাবে ছিষ্টেম এনিমেশ্বন সক্ষম কৰে। ইয়াৰ বাবে মেনিফেষ্ট ফাইলত প্ৰতি এপত enableOnBackInvokedCallback সত্য বুলি ছেট কৰাৰ প্ৰয়োজন।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index ca894e68e8f3..032251d15003 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Sıfırlayın"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Silin"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Qonaq məlumatı sıfırlanır…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Qonaq sessiyası sıfırlansın?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Bu, yeni qonaq sessiyası başladacaq və cari sessiyadan bütün tətbiqləri və datanı siləcək"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Qonaq rejimindən çıxılsın?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bununla cari qonaq sessiyasındakı bütün tətbiqlər və data silinəcək"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Çıxın"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Qonaq fəaliyyəti saxlansın?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Cari sessiyadakı fəaliyyəti saxlaya və ya bütün tətbiq və datanı silə bilərsiniz"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Silin"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Yadda saxlayın"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Qonaq rejimindən çıxın"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Qonaq sessiyasını sıfırlayın"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Qonaq rejimindən çıxın"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Çıxış zamanı bütün fəaliyyətlər silinəcək"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Çıxışda fəaliyyətinizi saxlaya və ya silə bilərsiniz"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Sessiya fəaliyyətini indi silmək üçün sıfırlayın və ya çıxışda fəaliyyəti saxlaya və ya silə bilərsiniz"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Foto seçin"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlayın"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Nəticəni dəyişdirin"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Proqnozlaşdırılan geri animasiyalar"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Proqnozlaşdırıcı geri jest üçün sistem animasiyalarını aktiv edin."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Bu ayar proqnozlaşdırıcı jest animasiyası üçün sistem animasiyalarını aktiv edir. Bu, manifest faylında hər bir tətbiq üçün enableOnBackInvokedCallback-in doğru kimi ayarlanmasını tələb edir."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 175842e8d6dc..9e7ef8951f52 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetuj"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ukloni"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Sesija gosta se resetuje…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Želite da resetujete sesiju gosta?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Time ćete pokrenuti novu sesiju gosta i izbrisati sve aplikacije i podatke iz aktuelne sesije"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Izaći ćete iz režima gosta?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Time ćete izbrisati sve aplikacije i podatke iz aktuelne sesije gosta"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izađi"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Sačuvaćete aktivnosti gosta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Sačuvajte aktivnosti iz aktuelne sesije ili izbrišite sve aplikacije i podatke"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Sačuvaj"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Izađi iz režima gosta"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Resetuj sesiju gosta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izađi iz režima gosta"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sve aktivnosti će biti izbrisane pri izlazu"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete da sačuvate ili izbrišete aktivnosti pri izlazu"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetujete za brisanje aktivnosti sesije, ili sačuvajte ili izbrišite aktivnosti pri izlazu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Izaberite sliku"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ako emitujete aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promenite izlaz, aktuelno emitovanje će se zaustaviti"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitujte aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Promenite izlaz"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacije za pokret povratka sa predviđanjem"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Omogućite animacije sistema za pokret povratka sa predviđanjem."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ovo podešavanje omogućava animacije sistema za pokret povratka sa predviđanjem. Zahteva podešavanje dozvole enableOnBackInvokedCallback po aplikaciji na true u fajlu manifesta."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 9bb441ab16fa..5da049d3e0fb 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Скінуць"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Выдаліць"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Ідзе скід гасцявога сеанса…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Скінуць гасцявы сеанс?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Будзе запушчаны новы гасцявы сеанс. Усе праграмы і даныя бягучага сеанса будуць выдалены"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Выйсці з гасцявога рэжыму?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Будуць выдалены праграмы і даныя бягучага гасцявога сеанса"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Выйсці"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Захаваць дзеянні госця?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Можна захаваць даныя пра дзеянні ў бягучым сеансе ці выдаліць праграмы і даныя"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Выдаліць"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Захаваць"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Выйсці з гасцявога рэжыму"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Скінуць гасцявы сеанс"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Выйсці з гасцявога рэжыму"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Падчас выхаду будуць выдалены ўсе звесткі пра дзеянні"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Падчас выхаду можна захаваць ці выдаліць звесткі пра дзеянні"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Скіньце звесткі пра дзеянні падчас сеанса зараз. Вы таксама можаце захаваць ці выдаліць іх у час выхаду."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зрабіць фота"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбраць відарыс"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Выбраць фота"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Трансляцыя праграмы \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Змяненне вываду"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Анімацыя падказкі для жэста вяртання"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Уключыць сістэмную анімацыю падказкі для жэстаў вяртання."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Гэта налада ўключае сістэмную анімацыю падказкі для жэста вяртання. Для гэтага неабходна задаць у файле маніфеста для параметра enableOnBackInvokedCallback значэнне \"True\" для кожнай праграмы."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 96ff08b623be..a894a840b3a5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Нулиране"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Премахване"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Сесията като гост се нулира…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Да се нулира ли сесията като гост?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Така ще стартирате нова сесия като гост и ще изтриете всички приложения и данни от текущата сесия"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Изход от режима на гост?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Така ще изтриете приложенията и данните от текущата сесия като гост"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Изход"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Запазване на активността като гост?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Можете да запазите активността от сесията или да изтриете всички прил. и данни"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Изтриване"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Запазване"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Изход от режима на гост"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Нулиране на сесията като гост"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Изход от сесията като гост"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Цялата активност ще бъде изтрита при изход"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"При изход можете да запазите активността или да я изтриете"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Нулирайте, за да изтриете активността в сесията сега. Можете също да я запазите или изтриете при изход"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Избиране на снимката"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Предаване на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Промяна на изхода"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Анимации за предвиждащия жест за връщане назад"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Активиране на системните анимации за предвиждащия жест за връщане назад."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Тази настройка активира системните анимации за предвиждащите жестове. За целта във файла на манифеста трябва да зададете enableOnBackInvokedCallback на true за отделните приложения."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 9cc930fbbdd1..9a2e44241ac8 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"রিসেট করুন"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"সরান"</string>
<string name="guest_resetting" msgid="7822120170191509566">"গেস্ট সেশন রিসেট করা হচ্ছে..."</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"অতিথি সেশন রিসেট করতে চান?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"এটি নতুন অতিথি সেশন চালু করবে এবং বর্তমান সেশন থেকে সব অ্যাপ ও ডেটা মুছে দেবে"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"\'অতিথি মোড\' ছেড়ে বেরিয়ে আসবেন?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"এটি বর্তমান অতিথি সেশন থেকে অ্যাপ ও ডেটা মুছে দেবে"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"বেরিয়ে আসুন"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"অতিথি মোডের অ্যাক্টিভিটি সেভ করবেন?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"আপনি বর্তমান সেশন থেকে অ্যাক্টিভিটি সেভ করতে বা সব অ্যাপ ও ডেটা মুছতে পারবেন"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"মুছুন"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"সেভ করুন"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"\'অতিথি মোড\' ছেড়ে বেরিয়ে আসুন"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"অতিথি সেশন রিসেট করুন"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"\'অতিথি মোড\' ছেড়ে বেরিয়ে আসুন"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ছেড়ে বেরিয়ে যাওয়ার সময় সব অ্যাক্টিভিটি মুছে দেওয়া হবে"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ছেড়ে বেরিয়ে যাওয়ার সময় আপনি অ্যাক্টিভিটি সেভ করতে পারবেন বা মুছতে পারবেন"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"সেশন অ্যাক্টিভিটি মুছে দিতে এখন রিসেট করুন বা ছেড়ে বেরিয়ে আসার সময় আপনি অ্যাক্টিভিটি সেভ করতে বা মুছতে পারবেন"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ফটো তুলুন"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"একটি ইমেজ বেছে নিন"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ফটো বেছে নিন"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"আপনি <xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করলে বা আউটপুট পরিবর্তন করলে, আপনার বর্তমান সম্প্রচার বন্ধ হয়ে যাবে"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করুন"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"আউটপুট পরিবর্তন করুন"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ফিরে যাওয়ার পূর্বাভাস সংক্রান্ত অ্যানিমেশন"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ফিরে যাওয়া সংক্রান্ত পূর্বাভাসের জন্য সিস্টেম অ্যানিমেশন চালু করুন।"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"জেসচারের পূর্বাভাস সংক্রান্ত অ্যানিমেশন দেখাতে এই সেটিং সিস্টেম অ্যানিমেশন চালু করে। এই সেটিংয়ে \'ম্যানিফেস্ট\' ফাইলে প্রত্যেক অ্যাপে enableOnBackInvokedCallback অ্যাট্রিবিউটকে \'ট্রু\' (true) হিসেবে সেট করতে হয়।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f8b14525d4c0..95557045b642 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -570,7 +570,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Ograničeni profil"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Dodati novog korisnika?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"Ovaj uređaj možete dijeliti s drugima ako napravite dodatne korisnike. Svaki korisnik ima svoj prostor koji može prilagoditi pomoću aplikacija, pozadinske slike i slično. Korisnici također mogu prilagoditi postavke uređaja koje utiču na sve ostale korisnike, kao što je WiFi.\n\nKada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike. Postavke i usluge pristupačnosti možda se neće prenijeti na novog korisnika."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor. \n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor. \n\n Svaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Postaviti korisnika sada?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Provjerite može li osoba uzeti uređaj i postaviti svoj prostor"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Postaviti profil sada?"</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Poništi"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ukloni"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Poništavanje sesije gosta…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Poništiti sesiju gosta?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Ovim ćete pokrenuti novu sesiju gosta i izbrisati sve aplikacije i podatke iz trenutne sesije"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Napustiti način rada za gosta?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ovim ćete izbrisati aplikacije i podatke iz trenutne sesije gosta"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Napusti"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Sačuvati aktivnost gosta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete sačuvati aktivnost iz ove sesije ili izbrisati sve aplikacije i podatke"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Sačuvaj"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Napusti način rada za gosta"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Poništi sesiju gosta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izlazak iz sesije gosta"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sva aktivnost će se izbrisati pri napuštanju"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete sačuvati ili izbrisati svoju aktivnost pri izlasku"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da odmah izbrišete aktivnost iz sesije ili je možete sačuvati ili izbrisati pri izlasku"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir fotografije"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitiraj aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Promijeni izlaz"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacije predvidljivog pokreta unazad"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Omogućite animacije sistema za predvidljivi pokret unazad."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ova postavka omogućava animacije sistema za animaciju predvidljivih pokreta. Potrebno je po aplikaciji postaviti vrijednost za enableOnBackInvokedCallback na tačno u fajlu deklaracije."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9387d0befbd4..ec32fa4aefa9 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Restableix"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Suprimeix"</string>
<string name="guest_resetting" msgid="7822120170191509566">"S\'està restablint el convidat…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vols restablir la sessió de convidat?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Aquesta acció iniciarà una nova sessió de convidat i suprimirà totes les aplicacions i dades de la sessió actual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Sortir del mode de convidat?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Aquesta acció suprimirà les aplicacions i dades de la sessió de convidat actual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Surt"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Desar l\'activitat de convidat?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Pots desar l\'activitat de la sessió actual o suprimir totes les apps i dades"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Suprimeix"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Desa"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Surt del mode de convidat"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Restableix la sessió de convidat"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Surt del mode de convidat"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Se suprimirà tota l\'activitat en sortir"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Pots desar o suprimir l\'activitat en sortir"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restableix la sessió per suprimir l\'activitat ara, o desa o suprimeix l\'activitat en sortir."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecciona una foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emet <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Canvia la sortida"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacions per a les accions de tornada predictives"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activa animacions del sistema per a la tornada predictiva."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Aquesta configuració activa animacions del sistema per a accions gestuals predictives. Requereix definir enableOnBackInvokedCallback com a \"true\" en cada aplicació al fitxer de manifest."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 52b492473455..6f75018e88f6 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetovat"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Odstranit"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetování hosta…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Resetovat relaci hosta?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Tímto zahájíte novou relaci hosta a smažete všechny aplikace a data z aktuální relace"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Ukončit režim hosta?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Tímto smažete aplikace a data z aktuální relace hosta"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Ukončit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Uložit aktivitu hosta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Aktivitu z aktuální relace můžete uložit, nebo všechny aplikace a data smazat"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Smazat"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Uložit"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Ukončit režim hosta"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Resetovat relaci hosta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ukončit režim hosta"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Veškerá aktivita bude při ukončení smazána"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Aktivitu můžete při ukončení uložit nebo smazat"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Aktivitu relace můžete ihned smazat resetováním, případně ji můžete uložit nebo smazat při ukončení"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Vybrat fotku"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Změna výstupu"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Prediktivní animace gesta Zpět"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Povolit systémové animace prediktivního gesta Zpět"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Toto nastavení aktivuje systémové prediktivní animace gest. Vyžaduje, aby v souborech manifestu jednotlivých aplikací byl nastaven atribut enableOnBackInvokedCallback na hodnotu True."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 34295fda2677..1b36b44aa105 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Nulstil"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Fjern"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Nulstiller gæst…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vil du nulstille gæstesessionen?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Denne handling starter en ny gæstesession og sletter alle apps og data fra den aktuelle session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Vil du afslutte gæstetilstanden?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Denne handling sletter apps og data fra den aktuelle gæstesession."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Luk"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vil du gemme gæsteaktiviteten?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Du kan gemme aktivitet fra den aktuelle session eller slette alle apps og data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Slet"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Gem"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Afslut gæstetilstand"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Nulstil gæstesession"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Afslut gæstesession"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Al aktivitet slettes ved afslutning"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan gemme eller slette din aktivitet ved afslutning"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nulstil for at slette sessionsaktiviteten nu, eller gem eller slet aktivitet ved afslutning"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vælg et billede"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Vælg billede"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Udsend <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Skift output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Foreslåede animationer for Tilbage"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktivér systemanimationer for foreslåede animationer for Tilbage."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Denne indstilling aktiverer systemanimationer for de foreslåede animationer for bevægelsen Tilbage. Dette forudsætter konfiguration af enableOnBackInvokedCallback som sand for hver app i manifestfilen."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 63d3c1eb3e09..267b6c2809c9 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Zurücksetzen"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Entfernen"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gast wird zurückgesetzt…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Gastsitzung zurücksetzen?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hierdurch wird eine neue Gastsitzung gestartet und alle Apps und Daten der aktuellen Sitzung werden gelöscht"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Gastmodus beenden?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Hierdurch werden Apps und Daten der aktuellen Gastsitzung gelöscht"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Beenden"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Gastaktivität speichern?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Speichere Aktivitäten der aktuellen Sitzung oder lösche alle Apps und Daten"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Löschen"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Speichern"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Gastmodus beenden"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Gastsitzung zurücksetzen"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Gastmodus beenden"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Beim Beenden werden alle Aktivitäten gelöscht"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Speichere oder lösche deine Aktivitäten beim Beenden"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Zurücksetzen, um jetzt die Sitzungsaktivitäten zu löschen, oder Aktivitäten beim Beenden speichern oder löschen"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto machen"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Bild auswählen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Foto auswählen"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Ausgabe ändern"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animationen für intelligente „Zurück“-Touch-Geste"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Du kannst Systemanimationen für die intelligente „Zurück“-Touch-Geste aktivieren."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Diese Einstellung aktiviert Systemanimationen für intelligente Touch-Gesten. Dazu muss in der Manifestdatei enableOnBackInvokedCallback auf App-Ebene auf „true“ gesetzt werden."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 1a7bb615b606..cfb6ecef1ff7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Επαναφορά"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Κατάργηση"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Επαναφορά επισκέπτη…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Επαναφορά περιόδου σύνδεσης επισκέπτη;"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Με αυτόν τον τρόπο θα ξεκινήσει μια νέα περίοδος σύνδεσης επισκέπτη και θα διαγραφούν όλες οι εφαρμογές και τα δεδομένα από την τρέχουσα περίοδο σύνδεσης"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Έξοδος από λειτ. επισκέπτη;"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Θα διαγραφούν εφαρμογές και δεδομένα από την τρέχουσα περίοδο σύνδεσης επισκέπτη"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Έξοδος"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Αποθήκευση δραστ. επισκέπτη;"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Αποθήκευση δραστ. τρέχουσας περιόδου σύνδεσης ή διαγραφή εφαρμογών και δεδομένων"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Διαγραφή"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Αποθήκευση"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Έξοδος από λειτ. επισκέπτη"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Επαναφορά περ. σύνδεσης επισκέπτη"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Έξοδος επισκέπτη"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Όλη η δραστηριότητα θα διαγραφεί κατά την έξοδο"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Αποθηκεύστε ή διαγράψτε τη δραστηριότητά σας κατά την έξοδο"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Επαναφορά για διαγραφή της δραστηριότητας της περιόδου σύνδεσης ή αποθήκευση ή διαγραφή κατά την έξοδο."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Επιλογή φωτογραφίας"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Εάν κάνετε μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g> ή αλλάξετε την έξοδο, η τρέχουσα μετάδοση θα σταματήσει"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Αλλαγή εξόδου"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Κινούμ. εικόνες μετάβασης προς τα πίσω με πρόβλεψη"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ενεργοποίηση κινούμενων εικόνων συστήματος για μετάβαση προς τα πίσω με πρόβλεψη."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Αυτή η ρύθμιση ενεργοποιεί τις κινούμενες εικόνες συστήματος για τις κινούμενες εικόνες κινήσεων με πρόβλεψη. Απαιτεί τη ρύθμιση της παραμέτρου enableOnBackInvokedCallback ως αληθούς σε κάθε εφαρμογή στο αρχείο μανιφέστου."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 506617b550bc..6b941dea4666 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remove"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Reset guest session?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"This will start a new guest session and delete all apps and data from the current session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Exit guest mode?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"This will delete apps and data from the current guest session"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Exit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Save guest activity?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"You can save activity from the current session or delete all apps and data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Delete"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Save"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Exit guest mode"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reset guest session"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Exit guest"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All activity will be deleted on exit"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"You can save or delete your activity on exit"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset to delete session activity now, or you can save or delete activity on exit"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Change output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Predictive back animations"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Enable system animations for predictive back."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"This setting enables system animations for predictive gesture animation. It requires setting per-app enableOnBackInvokedCallback to true in the manifest file."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index d8537fae95f3..549801df3765 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remove"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Reset guest session?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"This will start a new guest session and delete all apps and data from the current session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Exit guest mode?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"This will delete apps and data from the current guest session"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Exit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Save guest activity?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"You can save activity from the current session or delete all apps and data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Delete"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Save"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Exit guest mode"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reset guest session"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Exit guest"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All activity will be deleted on exit"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"You can save or delete your activity on exit"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset to delete session activity now, or you can save or delete activity on exit"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Change output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Predictive back animations"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Enable system animations for predictive back."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"This setting enables system animations for predictive gesture animation. It requires setting per-app enableOnBackInvokedCallback to true in the manifest file."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 506617b550bc..6b941dea4666 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remove"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Reset guest session?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"This will start a new guest session and delete all apps and data from the current session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Exit guest mode?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"This will delete apps and data from the current guest session"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Exit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Save guest activity?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"You can save activity from the current session or delete all apps and data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Delete"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Save"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Exit guest mode"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reset guest session"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Exit guest"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All activity will be deleted on exit"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"You can save or delete your activity on exit"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset to delete session activity now, or you can save or delete activity on exit"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Change output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Predictive back animations"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Enable system animations for predictive back."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"This setting enables system animations for predictive gesture animation. It requires setting per-app enableOnBackInvokedCallback to true in the manifest file."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 506617b550bc..6b941dea4666 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remove"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Reset guest session?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"This will start a new guest session and delete all apps and data from the current session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Exit guest mode?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"This will delete apps and data from the current guest session"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Exit"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Save guest activity?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"You can save activity from the current session or delete all apps and data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Delete"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Save"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Exit guest mode"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reset guest session"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Exit guest"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All activity will be deleted on exit"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"You can save or delete your activity on exit"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset to delete session activity now, or you can save or delete activity on exit"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Change output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Predictive back animations"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Enable system animations for predictive back."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"This setting enables system animations for predictive gesture animation. It requires setting per-app enableOnBackInvokedCallback to true in the manifest file."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index bb4de3da9300..2db3d9652a9f 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‎Reset‎‏‎‎‏‎"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎Remove‎‏‎‎‏‎"</string>
<string name="guest_resetting" msgid="7822120170191509566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎Resetting guest…‎‏‎‎‏‎"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎Reset guest session?‎‏‎‎‏‎"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎This will start a new guest session and delete all apps and data from the current session‎‏‎‎‏‎"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎Exit guest mode?‎‏‎‎‏‎"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎This will delete apps and data from the current guest session‎‏‎‎‏‎"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‎‎Exit‎‏‎‎‏‎"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎Save guest activity?‎‏‎‎‏‎"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎You can save activity from the current session or delete all apps and data‎‏‎‎‏‎"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎Delete‎‏‎‎‏‎"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎Save‎‏‎‎‏‎"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎Exit guest mode‎‏‎‎‏‎"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎Reset guest session‎‏‎‎‏‎"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎Exit guest‎‏‎‎‏‎"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎All activity will be deleted on exit‎‏‎‎‏‎"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎You can save or delete your activity on exit‎‏‎‎‏‎"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎Reset to delete session activity now, or you can save or delete activity on exit‎‏‎‎‏‎"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎Take a photo‎‏‎‎‏‎"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎Choose an image‎‏‎‎‏‎"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎Select photo‎‏‎‎‏‎"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎If you broadcast ‎‏‎‎‏‏‎<xliff:g id="SWITCHAPP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ or change the output, your current broadcast will stop‎‏‎‎‏‎"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎Broadcast ‎‏‎‎‏‏‎<xliff:g id="SWITCHAPP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎Change output‎‏‎‎‏‎"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎Predictive back animations‎‏‎‎‏‎"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎Enable system animations for predictive back.‎‏‎‎‏‎"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎This setting enables system animations for predictive gesture animation. It requires setting per-app enableOnBackInvokedCallback to true in the manifest file.‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index db0a617a08bb..64bab65e60e3 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Restablecer"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Quitar"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Restableciendo invitado…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"¿Quieres restablecer la sesión de invitado?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Esta acción comenzará una nueva sesión de invitado y borrará todas las apps y los datos de la sesión actual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"¿Salir del modo de invitado?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Esta acción borrará todas las apps y los datos de la sesión de invitado actual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Salir"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"¿Guardar actividad de invitado?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puedes guardar la actividad de la sesión actual o borrar las apps y los datos"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Borrar"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Guardar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Salir del modo de invitado"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Restablecer la sesión de invitado"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Salir del modo de invitado"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Cuando salgas, se borrará toda la actividad"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puedes guardar o borrar la actividad cuando salgas"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para eliminar la actividad ahora; o guarda o borra la actividad cuando salgas"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tomar una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Elegir una imagen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Cambia la salida"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animaciones de retroceso predictivas"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Habilitar animaciones del sistema para gestos de retroceso predictivos."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta configuración habilita las animaciones del sistema para la animación de gestos predictiva. Se requiere la configuración por app de enableOnBackInvokedCallback en verdadero en el archivo de manifiesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index d69b446c9ff9..3b38725edfcb 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Restablecer"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Quitar"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Restableciendo invitado…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"¿Restablecer sesión de invitado?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Se iniciará una nueva sesión de invitado y se borrarán todas las aplicaciones y datos de esta sesión"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"¿Salir del modo Invitado?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Se eliminarán todas las aplicaciones y datos de la sesión de invitado actual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Salir"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"¿Guardar actividad de invitado?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puedes guardar la actividad de esta sesión o eliminar todas las aplicaciones y datos"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eliminar"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Guardar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Salir del modo Invitado"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Restablecer sesión de invitado"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Salir del modo Invitado"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toda la actividad se eliminará cuando salgas"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puedes guardar o eliminar tu actividad al salir"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece la sesión para eliminar la actividad ahora, o guarda o borra la actividad al salir"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Cambiar salida"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animaciones para acciones de retorno predictivas"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Habilitar animaciones del sistema para acciones de retorno predictivas."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Este ajuste habilita animaciones del sistema para acciones gestuales predictivas. Exige definir el valor de enableOnBackInvokedCallback en \"verdadero\" para cada aplicación en el archivo de manifiesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 30f0350c9dd7..7af591c65177 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Lähtesta"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Eemalda"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Külastajaseansi lähtestamine …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Kas lähtestada külastajaseanss?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"See alustab uut külastajaseanssi ning kustutab kõik praeguse seansi rakendused ja andmed."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Kas väljuda külalisrežiimist?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"See kustutab praeguse külastajaseansi rakendused ja andmed"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Välju"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Kas salvestada külalise tegevus?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Võite selle seansi tegevused salvestada või kustutada kõik rakendused ja andmed."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Kustuta"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvesta"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Välju külalisrežiimist"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Lähtesta külastajaseanss"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Välju külastajaseansist"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Kõik tegevused kustutatakse väljumisel"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Võite tegevused salvestada või kustutada väljumisel."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Seansi tegevuste kohe kustutamiseks lähtestage; või salvestage või kustutage need väljumisel."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Valige foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Rakenduse <xliff:g id="SWITCHAPP">%1$s</xliff:g> ülekandmine"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Väljundi muutmine"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Tagasiliigutuse prognoosi animatsioon"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Lubage süsteemi animatsioonid, et näha prognoositud tagasiliigutusi."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"See seade võimaldab süsteemi animatsioonidel prognoosida tagasiliigutusi. See nõuab manifestifailis rakendusepõhise atribuudi enableOnBackInvokedCallback määramist tõeseks."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 3a38abdc307f..a8205f359547 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Berrezarri"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Kendu"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gonbidatuentzako saioa berrezartzen…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Gonbidatuentzako saioa berrezarri nahi duzu?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Gonbidatuentzako saio berri bat abiaraziko da, eta saio honetako aplikazio eta datu guztiak ezabatuko"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Gonbidatu modutik irten nahi duzu?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Gonbidatuentzako saio honetako aplikazioak eta datuak ezabatuko dira"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Irten"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Gonbidatuaren jarduerak gorde nahi dituzu?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Saio honetako jarduerak gorde ditzakezu, edo aplikazio eta datu guztiak ezabatu"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Ezabatu"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Gorde"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Irten gonbidatu modutik"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Berrezarri gonbidatuentzako saioa"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Irten gonbidatu modutik"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Irtetean, jarduera guztiak ezabatuko dira"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Irtetean, jarduerak gorde edo ezabatu egin ditzakezu"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Berrezarri saioa jarduerak ezabatzeko; bestela, aukeratu jarduerak irtetean gordetzea edo ezabatzea"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Hautatu argazki bat"</string>
@@ -653,10 +668,7 @@
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Eman pantaila pizteko baimena"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Eman pantaila pizteko baimena aplikazioei. Baimena emanez gero, aplikazioek edonoiz piztu ahal izango dute pantaila, zuk halako asmorik izan ez arren."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
- <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen edo audio-irteera aldatzen baduzu, une hartako igorpena etengo da"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Igorri <xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Aldatu audio-irteera"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Atzera egiteko keinuaren animazio-igarleak"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Gaitu atzera egiteko keinuaren sistemaren animazio-igarleak."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Atzera egiteko keinuaren sistemaren animazio-igarleak gaitzen ditu ezarpenak. enableOnBackInvokedCallback-ek egiazko gisa ezarrita egon behar du aplikazio bakoitzaren manifestu-fitxategian."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 04549b2d46f4..b9b103f934b8 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"بازنشانی"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"برداشتن"</string>
<string name="guest_resetting" msgid="7822120170191509566">"درحال بازنشانی مهمان…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"جلسه مهمان بازنشانی شود؟"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"با این کار، جلسه مهمان جدیدی شروع خواهد شد و همه برنامه‌ها و داده‌ها از جلسه کنونی حذف خواهند شد"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"از حالت مهمان خارج می‌شوید؟"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"با این کار، برنامه‌ها و داده‌ها از جلسه مهمان کنونی حذف خواهند شد."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"خروج"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"فعالیت مهمان ذخیره شود؟"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"می‌توانید فعالیت جلسه کنونی را ذخیره کنید یا همه برنامه و داده‌ها را حذف کنید"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"حذف"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ذخیره"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"خروج از حالت مهمان"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"بازنشاندن جلسه مهمان"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"خروج مهمان"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"همه فعالیت‌ها هنگام خروج حذف خواهد شد"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"می‌توانید فعالیتتان را هنگام خروج ذخیره یا حذف کنید"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"برای حذف فعالیت جلسه در این لحظه، بازنشانی کنید یا می‌توانید فعالیت را هنگام خروج ذخیره یا حذف کنید"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"عکس گرفتن"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"انتخاب تصویر"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"انتخاب عکس"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همه‌فرستی کنید یا خروجی را تغییر دهید، همه‌فرستی کنونی متوقف خواهد شد"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"همه‌فرستی <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"تغییر خروجی"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"پویانمایی‌های اشاره برگشت پیش‌بینانه"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"پویانمایی‌های سیستم را برای اشاره برگشت پیش‌بینانه فعال کنید."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏این تنظیم پویانمایی‌های سیستم را برای پویانمایی اشاره برگشت پیش‌بینانه فعال می‌کند. این تنظیم مستلزم تنظیم شدن enableOnBackInvokedCallback مربوط به هر برنامه روی صحیح در فایل مانیفست است."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index b643784cbbe2..6f8300d59fe8 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Nollaa"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Poista"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Nollataan vierasta…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Nollataanko vierailija-käyttökerta?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Tämä aloittaa uuden vierailija-käyttökerran ja kaikki nykyisen istunnon sovellukset ja data poistetaan"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Poistutaanko vierastilasta?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Tämä poistaa nykyisen vierailija-käyttökerran sovellukset ja datan"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sulje"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Tallennetaanko vierastoiminta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Voit tallentaa tämän istunnon toimintaa tai poistaa kaikki sovellukset ja datan"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Poista"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Tallenna"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Poistu vierastilasta"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Nollaa vierailija-käyttökerta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Kirjaa vieras ulos"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Kaikki toiminta poistetaan uloskirjaamisen aikana"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Voit tallentaa tai poistaa toiminnan poistuessasi"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nollaa poistaaksesi istunnon toiminnan nyt, tai voit tallentaa tai poistaa toimintaa poistuessasi"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Valitse kuva"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Lähetä <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Muuta ulostuloa"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Takaisin siirtymisen ennakoivat animaatiot"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ota käyttöön takaisin siirtymisen ennakoivat järjestelmäanimaatiot."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Asetus ottaa järjestelmäanimaatiot käyttöön ennakoiville eleanimaatioille. Se edellyttää, että enableOnBackInvokedCallback-arvo on Tosi sovelluksen manifestitiedostossa."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 5325fbc2df41..024c189b1891 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Réinitialiser"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Retirer"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Réinitialisation de la session Invité en cours…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Réinitialiser la session d\'invité?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Une nouvelle session d\'invité sera lancée, et toutes les applications et données de la session en cours seront supprimées"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Quitter le mode Invité?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Les applications et les données de la session d\'invité en cours seront supprimées"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Quitter"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Enregistrer l\'activité d\'invité?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Vous pouvez enregistrer l\'activité de session ou supprimer les applis et données"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Supprimer"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Enregistrer"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Quitter le mode Invité"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Réinitialiser la session d\'invité"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Quitter la session d\'invité"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toute l\'activité sera supprimée à la fin de la session"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Vous pouvez enregistrer ou supprimer votre activité à la fin"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Réinitialisez pour supprimer l\'activité de la session maintenant, ou vous pouvez enregistrer ou supprimer l\'activité à la fin de la session"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Sélectionner une image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Sélectionnez une photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Changer la sortie"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animations pour le retour prédictif"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activer les animations système pour le retour prédictif."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre permet d\'activer les animations du système pour l\'animation des gestes prédictifs. Cela exige de définir le paramètre enableOnBackInvokedCallback à Vrai pour chaque application dans le fichier de configuration."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b667fc0519b2..2073763e0200 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -185,7 +185,7 @@
<string name="launch_defaults_none" msgid="8049374306261262709">"Aucun paramètre par défaut défini"</string>
<string name="tts_settings" msgid="8130616705989351312">"Paramètres de la synthèse vocale"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Sortie de la synthèse vocale"</string>
- <string name="tts_default_rate_title" msgid="3964187817364304022">"Débit"</string>
+ <string name="tts_default_rate_title" msgid="3964187817364304022">"Cadence"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Vitesse à laquelle le texte est énoncé"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Ton"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"Affecte le ton utilisé pour la synthèse vocale"</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Réinitialiser"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Supprimer"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Réinitialisation de la session Invité…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Réinitialiser la session Invité ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Cette action lancera une nouvelle session Invité et supprimera toutes les applis et données de la session actuelle"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Quitter le mode Invité ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Cette action supprimera les applis et données de la session Invité actuelle."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Quitter"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Enregistrer l\'activité ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Enregistrez l\'activité de la session actuelle ou supprimez les applis et données"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Supprimer"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Enregistrer"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Quitter le mode Invité"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Réinitialiser la session Invité"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Quitter le mode Invité"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toute l\'activité sera supprimée à la fin de la session"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Vous pouvez enregistrer ou supprimer l\'activité en quittant"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Réinitialisez la session pour supprimer immédiatement l\'activité. Vous pourrez aussi l\'enregistrer ou la supprimer en quittant la session."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choisir une image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Sélectionner une photo"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Modifier le résultat"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animations pour prévisualiser le retour en arrière"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activer les animations système pour la prévisualisation du geste de retour."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre active les animations système pour la prévisualisation du geste de retour. Pour cela, enableOnBackInvokedCallback doit être défini sur \"True\" dans le fichier manifeste de chaque appli."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index da66e922543e..f0cac1261aae 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Restablecer"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Quitar"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Restablecendo sesión de convidado…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Queres restablecer a sesión de convidado?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Iniciarase unha nova sesión de convidado e eliminaranse todas as aplicacións e datos desta sesión"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Saír do modo de convidado?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Eliminaranse as aplicacións e os datos da sesión de convidado actual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Saír"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Gardar actividade do convidado?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Podes gardar a actividade da sesión ou eliminar todas as aplicacións e datos"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eliminar"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Gardar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Saír do modo de convidado"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Restablecer sesión de convidado"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Saír do modo de convidado"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Eliminarase toda a actividade ao saír"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Podes gardar ou eliminar a túa actividade ao saír"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Restablece a sesión para eliminar a actividade agora, ou ben gárdaa ou elimínaa ao saír"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleccionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitir contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Cambiar de saída"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacións para o xesto preditivo de volver atrás"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activa as animacións do sistema para o xesto preditivo de volver atrás."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta opción de configuración activa as animacións do sistema para o xesto preditivo de volver atrás. É preciso definir enableOnBackInvokedCallback como True (verdadeiro) para cada aplicación no ficheiro de manifesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index de2fc038cfd3..6e5c6a436a60 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"રીસેટ કરો"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"કાઢી નાખો"</string>
<string name="guest_resetting" msgid="7822120170191509566">"અતિથિને રીસેટ કરી રહ્યાં છીએ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"શું અતિથિ સત્ર રીસેટ કરીએ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"આમ કરવાથી કોઈ નવું અતિથિ સત્ર ચાલુ થશે તેમજ હાલના સત્રમાંની તમામ ઍપ અને ડેટા ડિલીટ થશે"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"શું અતિથિ મોડમાંથી બહાર નીકળીએ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"આમ કરવાથી હાલના અતિથિ સત્રની તમામ ઍપ અને ડેટા ડિલીટ કરવામાં આવશે"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"બહાર નીકળો"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"શું અતિથિ પ્રવૃત્તિ સાચવીએ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"તમે હાલના સત્રની પ્રવૃત્તિ સાચવી શકો છો અથવા તમામ ઍપ અને ડેટા ડિલીટ કરી શકો છો"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ડિલીટ કરો"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"સાચવો"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"અતિથિ મોડમાંથી બહાર નીકળો"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"અતિથિ સત્ર રીસેટ કરો"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"અતિથિ મોડમાંથી બહાર નીકળો"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"બહાર નીકળતી વખતે તમામ પ્રવૃત્તિ ડિલીટ કરવામાં આવશે"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"બહાર નીકળતી વખતે તમે પ્રવૃત્તિ સાચવી કે ડિલીટ કરી શકશો"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"સત્રની પ્રવૃત્તિ હમણાં ડિલીટ કરવા માટે રીસેટ કરો અથવા બહાર નીકળતી વખતે તમે પ્રવૃત્તિ સાચવી કે ડિલીટ કરી શકશો"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ફોટો લો"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"છબી પસંદ કરો"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ફોટો પસંદ કરો"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"જો તમે <xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો અથવા આઉટપુટ બદલો, તો તમારું હાલનું બ્રોડકાસ્ટ બંધ થઈ જશે"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"આઉટપુટ બદલો"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"પાછળના પૂર્વાનુમાનિત ઍનિમેશન્સ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"પાછળના પૂર્વાનુમાનિત સંકેત માટે સિસ્ટમ ઍનિમેશન ચાલુ કરો."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"આ સેટિંગ પૂર્વાનુમાનિત સંકેત ઍનિમેશન માટે સિસ્ટમ ઍનિમેશન ચાલુ કરે છે. તેના માટે દરેક ઍપ માટે મેનિફેસ્ટ ફાઇલમાં enableOnBackInvokedCallbackને true પર સેટ કરવાની જરૂર પડે છે."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9eccbf99e6b2..43226c2a9192 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"रीसेट करें"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"हटाएं"</string>
<string name="guest_resetting" msgid="7822120170191509566">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट किया जा रहा है…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"क्या मेहमान मोड के मौजूदा सेशन को रीसेट करना है?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ऐसा करने पर, मेहमान के तौर पर ब्राउज़ करने का एक नया सेशन शुरू हो जाएगा. साथ ही, पिछले सेशन में मौजूद डेटा और इस्तेमाल किए जा रहे ऐप्लिकेशन को मिटा दिया जाएगा"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"मेहमान मोड से बाहर निकलना है?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"इससे, मेहमान मोड के मौजूदा सेशन का डेटा और इसमें इस्तेमाल हो रहे ऐप मिट जाएंगे"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"बाहर निकलें"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"मेहमान मोड की गतिविधि को सेव करना है?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"मौजूदा सेशन की गतिविधि को सेव किया जा सकता है या सभी ऐप और डेटा को मिटाया जा सकता है"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"मिटाएं"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"सेव करें"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"मेहमान मोड से बाहर निकलें"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"मेहमान मोड के सेशन को रीसेट करें?"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"मेहमान मोड से बाहर निकलें"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"बाहर निकलने पर, सारी गतिविधि मिट जाएगी"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"बाहर निकलने पर, गतिविधि को मिटाया या सेव किया जा सकता है"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"सेशन की गतिविधि को अभी मिटाने के लिए, रीसेट करें. इसके अलावा, बाहर निकलने पर, गतिविधि को मिटाया या सेव किया जा सकता है"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"फ़ोटो चुनें"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट करें"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"आउटपुट बदलें"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"प्रिडिक्टिव बैक ऐनिमेशन"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"प्रिडिक्टिव बैक के लिए सिस्टम ऐनिमेशन चालू करें."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"यह सेटिंग, सिस्टम के ऐनिमेशन को प्रिडिक्टिव जेस्चर ऐनिमेशन के लिए चालू कर देती है. मेनिफ़ेस्ट फ़ाइल में enableOnBackInvokedCallback की सेटिंग को हर ऐप्लिकेशन के हिसाब से \'सही\' पर सेट होना चाहिए."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ffd276b5c351..db34075b0909 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Poništi"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ukloni"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Poništavanje gostujuće sesije…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Želite li poništiti gostujuću sesiju?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Time će se pokrenuti nova gostujuća sesija i izbrisati sve aplikacije i podaci iz trenutačne sesije."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Napustiti način rada za goste?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Time će se izbrisati aplikacije i podaci iz trenutačne gostujuće sesije."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izlaz"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Spremiti aktivnosti gosta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete spremiti aktivnosti iz ove sesije ili izbrisati sve aplikacije i podatke"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Spremi"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Izlaz iz načina rada za goste"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Poništi gostujuću sesiju"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izlaz iz gostujuće sesije"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sve će se aktivnosti izbrisati na izlasku"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Svoje aktivnosti možete spremiti ili izbrisati na izlasku."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Poništite da odmah izbrišete aktivnost sesije. Inače je možete spremiti ili izbrisati na izlasku."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir slike"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, vaše će se trenutačno emitiranje zaustaviti"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitiranje aplikacije <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Promjena izlaza"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacije za pokret povratka s predviđanjem"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Omogući animacije sustava za pokret povratka s predviđanjem."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ova postavka omogućuje animacije sustava za animaciju pokreta s predviđanjem. Zahtijeva postavljanje dopuštenja enableOnBackInvokedCallback po aplikaciji na True u datoteci manifesta."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c613d0a7197e..5528ee9ac2fe 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Visszaállítás"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Eltávolítás"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Vendég munkamenet visszaállítása…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Visszaállítja a vendégmunkamenetet?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"A művelettel új vendégmunkamenetet indít, valamint az összes alkalmazást és adatot törli az aktuális munkamenetből"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Kilép a vendég módból?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"A művelettel törlődnek az aktuális vendégmunkamenet alkalmazásai és adatai"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Kilépés"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Menti a vendégtevékenységeket?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Tevékenységeket menthet az aktuális munkamenetből, vagy minden appot és adatot törölhet"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Törlés"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Mentés"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Kilépés a vendég módból"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Vendégmunkamenet visszaállítása"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Vendég kiléptetése"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"A kilépéssel minden tevékenység törlődik"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"A kilépéskor mentheti vagy törölheti a tevékenységeket"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Visszaállítással azonnal törölheti, illetve kilépéskor mentheti vagy törölheti a tevékenységeket"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Fotó kiválasztása"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Kimenet módosítása"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Prediktív „vissza” kézmozdulat-animációk"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Rendszeranimációk engedélyezése prediktív „vissza” kézmozdulatok esetén."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"A beállítás engedélyezi a rendszeranimációkat a prediktív kézmozdulat-animációk esetén. A használatukhoz az enableOnBackInvokedCallback beállítást true értékre kell állítani az egyes alkalmazások manifestfájljaiban."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index c7a8e4d3727a..a536d2103bb4 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -338,7 +338,7 @@
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Ստուգել հավելվածները USB-ի նկատմամբ"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Ստուգել հավելվածների անվտանգությունը ADB/ADT-ի միջոցով տեղադրված լինելու դեպքում։"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Bluetooth սարքերը կցուցադրվեն առանց անունների (միայն MAC հասցեները)"</string>
- <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ, երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ՝ երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Միացնել Bluetooth Gabeldorsche գործառույթի զտիչը"</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Միացնում է «Տվյալների լավացված փոխանակում» գործառույթը։"</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Տեղային տերմինալ"</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Զրոյացնել"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Հեռացնել"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Հյուրի աշխատաշրջանը վերակայվում է…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Զրոյացնե՞լ հյուրի աշխատաշրջանը"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Կսկսվի հյուրի նոր աշխատաշրջան, իսկ նախորդ աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Դուրս գա՞լ հյուրի ռեժիմից"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Հյուրի ընթացիկ աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Դուրս գալ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Պահե՞լ հյուրի ռեժիմի պատմությունը"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Պահեք ընթացիկ աշխատաշրջանի պատմությունը կամ ջնջեք հավելվածներն ու տվյալները"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Ջնջել"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Պահել"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Դուրս գալ հյուրի ռեժիմից"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Զրոյացնել հյուրի աշխատաշրջանը"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Դուրս գալ հյուրի ռեժիմից"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Եթե դուրս գաք, ամբողջ պատմությունը կջնջվի"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Դուրս գալիս կարող եք պահել կամ ջնջել ձեր պատմությունը"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Վերակայեք աշխատաշրջանի պատմությունը հիմա կամ պահեք/ջնջեք այն դուրս գալիս"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Լուսանկարել"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Ընտրել պատկեր"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Ընտրեք լուսանկար"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Հեռարձակել <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Փոխել աուդիո ելքը"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"«Հետ» ժեստի հուշման շարժանկարներ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Միացնել համակարգի անիմացիաները «Հետ» ժեստի հուշման համար"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Այս կարգավորման միջոցով կարելի է միացնել համակարգային շարժանկարները ժեստի հուշման համար։ Կարգավորումը պահանջում է մանիֆեստի ֆայլում սահմանել true արժեքը per-app enableOnBackInvokedCallback հատկության համար։"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3104fe17908b..5d311fb91ffe 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Hapus"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Mereset tamu …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Reset sesi tamu?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Tindakan ini akan memulai sesi tamu baru dan menghapus semua aplikasi serta data dari sesi saat ini"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Keluar dari mode tamu?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Tindakan ini akan menghapus aplikasi dan data dari sesi tamu saat ini"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Keluar"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Simpan aktivitas tamu?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Anda bisa menyimpan aktivitas sesi saat ini atau menghapus semua aplikasi &amp; data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Hapus"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Simpan"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Keluar dari mode tamu"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reset sesi tamu"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Keluar dari mode tamu"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Semua aktivitas akan dihapus saat Anda keluar"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Anda dapat menyimpan atau menghapus aktivitas saat keluar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reset untuk hapus aktivitas sesi sekarang, atau simpan atau hapus aktivitas saat keluar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih gambar"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Ubah output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animasi kembali prediktif"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktifkan animasi sistem untuk kembali prediktif."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Setelan ini mengaktifkan animasi sistem untuk animasi gestur prediktif. Setelan ini mewajibkan enableOnBackInvokedCallback per-aplikasi disetel ke benar (true) dalam file manifes."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index c48142490512..cac0b071028b 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Endurstilla"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Fjarlægja"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Endurstillir gest…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Endurstilla gestalotu?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Þetta opnar nýja gestalotu og eyðir öllum forritum og gögnum úr núverandi lotu"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Loka gestastillingu?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Þetta eyðir forritum og gögnum úr núverandi gestalotu"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Hætta"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vista aðgerðir úr gestalotu?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Þú getur vistað aðgerðir úr núverandi lotu eða eytt öllum forritum og gögnum"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eyða"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Vista"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Loka gestastillingu"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Endurstilla gestalotu"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Loka gestastillingu"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Öllum aðgerðum verður eytt þegar lotu er lokað"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Þú getur vistað eða eytt aðgerðum þegar þú lokar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Endurstilltu til að eyða aðgerðum lotu núna, eða vistaðu eða eyddu aðgerðum þegar þú lokar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Velja mynd"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Senda út <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Skipta um úttak"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Hreyfimyndir flýtiritunar við bendinguna „til baka“"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Kveikja á hreyfimyndum í kerfinu til að sýna hreyfimyndir þegar bendingin „til baka“ er gerð."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Þessi stilling kveikir á hreyfimyndum í kerfinu til að sýna hreyfimyndir flýtiritunar með bendingum. Stillingin krefst þess að kveikt sé á enableOnBackInvokedCallback í upplýsingaskránni fyrir hvert forrit."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 87fc4b7392e7..4caab7fe6622 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reimposta"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Rimuovi"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Reimpostazione sessione Ospite in corso…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vuoi reimpostare la sessione Ospite?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Verrà avviata una nuova sessione Ospite e verranno eliminati tutti i dati e le app della sessione corrente"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Vuoi uscire da modalità Ospite?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Verranno eliminati i dati e le app della sessione Ospite corrente"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Esci"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vuoi salvare l\'attività Ospite?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puoi salvare l\'attività della sessione corrente o eliminare tutti i dati e le app"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Elimina"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salva"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Esci dalla modalità Ospite"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Reimposta sessione Ospite"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Esci dalla modalità Ospite"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Quando esci verrà eliminata tutta l\'attività"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Quando esci puoi salvare o eliminare la tua attività"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reimposta la sessione per eliminare subito l\'attività, oppure salvala o eliminala quando esci"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Seleziona la foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Cambia uscita"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animazioni predittive con Indietro"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Attiva le animazioni di sistema per il gesto Indietro predittivo."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Questa impostazione attiva le animazioni di sistema per il gesto Indietro predittivo. Richiede di impostare il metodo enableOnBackInvokedCallback su true nel file manifest di tutte le app."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 5c3c304ffacd..3dfe0ba1498b 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"איפוס"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"הסרה"</string>
<string name="guest_resetting" msgid="7822120170191509566">"מתבצע איפוס של הגלישה כאורח…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"לאפס את הגלישה כאורח?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"הפעולה הזו תתחיל גלישה חדשה כאורח ותמחק את כל האפליקציות והנתונים מהסשן הנוכחי"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"לצאת ממצב אורח?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"הפעולה הזו תמחק את האפליקציות והנתונים מהגלישה הנוכחית כאורח"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"יציאה"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"לשמור את פעילות האורח?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"אפשר לשמור את הפעילות מהסשן הנוכחי או למחוק את כל האפליקציות והנתונים"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"מחיקה"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"שמירה"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"יציאה ממצב אורח"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"איפוס הגלישה כאורח"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"יציאה ממצב אורח"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"כל הפעילות תימחק ביציאה"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"אפשר לשמור או למחוק את הפעילות שלך ביציאה"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ניתן לאפס כדי למחוק את הפעילות מהסשן כעת, או לשמור או למחוק את הפעילות ביציאה"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"צילום תמונה"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"לבחירת תמונה"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"בחירת תמונה"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"שידור תוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"שינוי הפלט"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"חיזוי אנימציה של תנועת החזרה"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"הפעלת אנימציות מערכת עבור חיזוי של תנועת החזרה."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏ההגדרה הזו מפעילה אנימציות מערכת עבור חיזוי אנימציה של תנועת החזרה. היא מחייבת הגדרה בכל אפליקציה של ערך true בשדה enableOnBackInvokedCallback בקובץ המניפסט."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index cf112379e68a..78dfb8e2feb3 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"リセット"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"削除"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ゲストをリセットしています…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ゲスト セッションをリセットしますか?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"新しいゲスト セッションが開始し、現在のセッションのすべてのアプリとデータが削除されます"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ゲストモードを終了しますか?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"現在のゲスト セッションからすべてのアプリとデータが削除されます"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"終了"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ゲストアクティビティの保存"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"現在のセッションのアクティビティの保存や、すべてのアプリとデータの削除を行えます"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"削除"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"保存"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ゲストモードを終了"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ゲスト セッションをリセット"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ゲストを終了"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"終了時にすべてのアクティビティが削除されます"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"終了時にアクティビティを保存、削除できます"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"アクティビティは、リセットして今すぐ削除するか、終了時に保存または削除できます"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"写真を撮る"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"画像を選択"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"写真を選択"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャストしたり、出力を変更したりすると、現在のブロードキャストが停止します。"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャスト"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"出力を変更"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"予測型「戻る」アニメーション"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"予測型「戻る」のシステム アニメーションを有効にする。"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"この設定は、予測型操作のシステム アニメーションを有効にします。アプリごとにマニフェスト ファイルで enableOnBackInvokedCallback を true に設定する必要があります。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 540f1fc870d6..cb5a8ce15308 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"გადაყენება"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ამოშლა"</string>
<string name="guest_resetting" msgid="7822120170191509566">"მიმდინარეობს სტუმრის გადაყენება…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"გსურთ სტუმრის სესიის გადაყენება?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ამ ქმედებით დაიწყება სტუმრის ახალი სესია და წაიშლება ყველა აპი და მონაცემი მიმდინარე სესიიდან"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"გსურთ სტუმრის რეჟიმიდან გასვლა?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ეს ქმედება წაშლის აპებსა და მონაცემებს სტუმრის რეჟიმის მიმდინარე სესიიდან"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"გასვლა"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"გსურთ სტუმრის აქტივობის შენახვა?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"შეგიძლიათ შეინახოთ აქტივობა მიმდინარე სესიიდან ან წაშალოთ ყველა აპი და მონაცემი"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"წაშლა"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"შენახვა"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"სტუმრის რეჟიმიდან გასვლა"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"სტუმრის სესიის გადაყენება"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"სტუმრის გასვლა"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"გასვლისას ყველა აქტივობა წაიშლება"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"გასვლისას შეგიძლიათ შეინახოთ ან წაშალოთ თქვენი აქტივობა"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"გადააყენეთ სესიის აქტივობის ახლა წასაშლელად. შენახვა/წაშლა გასვლისასაც შეიძლება."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ფოტოს გადაღება"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"აირჩიეთ სურათი"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ფოტოს არჩევა"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაციის შემთხვევაში ან აუდიოს გამოსასვლელის შეცვლისას, მიმდინარე ტრანსლაცია შეჩერდება"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაცია"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"აუდიოს გამოსასვლელის შეცვლა"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"უკან დაბრუნების ანიმაციის პროგნოზირება"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"უკან დაბრუნების პროგნოზირებადი ანიმაციისთვის სისტემის ანიმაციების ჩართვა."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ეს პარამეტრი ჩართავს სისტემის ანიმაციებს ჟესტების პროგნოზირებადი ანიმაციებისთვის. საჭიროა, რომ აღწერის ფაილში აპის enableOnBackInvokedCallback პარამეტრი იყოს ჭეშმარიტი."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 22774799a853..a47b49e095a0 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Бастапқы күйге қайтару"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Өшіру"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Қонақ сеансы бастапқы күйге қайтарылуда…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Қонақ сеансын бастапқы күйге қайтару керек пе?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Мұндайда жаңа қонақ сеансы басталады және ағымдағы сеанстағы барлық қолданба мен дерек жойылады."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Қонақ режимінен шығу керек пе?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ағымдағы қонақ сеансындағы барлық қолданба мен дерек жойылады."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Шығу"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Қонақ әрекетін сақтау керек пе?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Ағымдағы сеанстағы әрекетті сақтай не барлық қолданба мен деректі жоя аласыз."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Жою"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сақтау"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Қонақ режимінен шығу"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Қонақ режимін қалпына келтіру"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Қонақ режимінен шығу"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Шыққанда барлық әрекет жойылады."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Шыққанда барлық әрекетті сақтай немесе жоя аласыз."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанс дерегін жою үшін оны бастапқы күйге қайтарыңыз. Деректі шығар кезде де сақтауға не жоюға болады."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Фотосурет таңдау"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын тарату"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Аудио шығысын өзгерту"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"\"Артқа\" қимылына арналған тұспал анимациясы"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"\"Артқа\" қимылына арналған жүйелік тұспал анимацияларын іске қосу."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Бұл параметр қимылға арналған жүйелік тұспал анимацияларын іске қосады. Ол үшін әр қолданбаның манифест файлында enableOnBackInvokedCallback үшін \"True\" мәні қойылуы керек."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index eb8ae476b986..5a0d83a37e3b 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"កំណត់​ឡើងវិញ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ដកចេញ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"កំពុងកំណត់​ភ្ញៀវឡើងវិញ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"កំណត់វគ្គភ្ញៀវឡើងវិញឬ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ការធ្វើបែបនេះនឹងចាប់ផ្ដើមវគ្គភ្ញៀវថ្មី និងលុបកម្មវិធី និងទិន្នន័យទាំងអស់ចេញពីវគ្គបច្ចុប្បន្ន"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ចាកចេញពីមុខងារភ្ញៀវឬ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ការធ្វើបែបនេះនឹងលុបកម្មវិធី និងទិន្នន័យចេញពីវគ្គភ្ញៀវបច្ចុប្បន្ន"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ចាកចេញ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"រក្សាទុកសកម្មភាពភ្ញៀវឬ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"អ្នកអាចរក្សាទុកសកម្មភាពពីវគ្គបច្ចុប្បន្ន ឬលុបកម្មវិធីនិងទិន្នន័យទាំងអស់"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"លុប"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"រក្សាទុក"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ចាកចេញពីមុខងារភ្ញៀវ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"កំណត់វគ្គភ្ញៀវឡើងវិញ"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ចាកចេញពីមុខងារភ្ញៀវ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"សកម្មភាពទាំងអស់នឹងត្រូវលុបនៅពេលចាកចេញ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"អ្នកអាចរក្សាទុក ឬលុបសកម្មភាពរបស់អ្នកនៅពេលចាកចេញ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"កំណត់ឡើងវិញ ដើម្បីលុបសកម្មភាពក្នុងវគ្គឥឡូវនេះ ឬអ្នកអាចរក្សាទុកឬលុបសកម្មភាពនៅពេលចាកចេញ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើស​រូបភាព"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ជ្រើសរើស​​រូបថត"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ប្រសិនបើអ្នក​ផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹង​បញ្ឈប់"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"ការផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ប្ដូរឧបករណ៍បញ្ចេញសំឡេង"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ចលនា​ថយក្រោយ​ដែល​ព្យាករ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"បើក​ចលនា​ប្រព័ន្ធ​សម្រាប់​ការ​ថយក្រោយ​ព្យាករ។"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ការ​កំណត់នេះ​បើក​ចលនា​ប្រព័ន្ធ​សម្រាប់​ចលនាព្យាករ។ ចលនា​នេះ​ទាមទារ​ការ​កំណត់ enableOnBackInvokedCallback នៅ​ក្នុងកម្មវិធី​ទៅពិត​នៅ​ក្នុង​ឯកសារ​មេនីហ្វេសថ៍។"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 0536960094d1..02c34afd55b7 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ರೀಸೆಟ್ ಮಾಡಿ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ಅತಿಥಿ ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ರೀಸೆಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ಅತಿಥಿ ಸೆಷನ್ ಅನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೇ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ಈ ಪ್ರಕ್ರಿಯೆಯು ಹೊಸ ಅತಿಥಿ ಸೆಶನ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರಸ್ತುತ ಸೆಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳು ಹಾಗೂ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ಅತಿಥಿ ಮೋಡ್‌ನಿಂದ ನಿರ್ಗಮಿಸಬೇಕೆ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ಈ ಪ್ರಕ್ರಿಯೆಯು ಪ್ರಸ್ತುತ ಅತಿಥಿ ಸೆಷನ್‌ನಿಂದ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ನಿರ್ಗಮಿಸಿ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ಅತಿಥಿ ಚಟುವಟಿಕೆಯನ್ನು ಉಳಿಸಬೇಕೆ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"ನೀವು ಪ್ರಸ್ತುತ ಸೆಶನ್‌ನ ಚಟುವಟಿಕೆಯನ್ನು ಉಳಿಸಬಹುದು ಅಥವಾ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಬಹುದು"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ಅಳಿಸಿ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ಉಳಿಸಿ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ಅತಿಥಿ ಮೋಡ್‌ನಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ಅತಿಥಿ ಸೆಷನ್ ಅನ್ನು ರೀಸೆಟ್ ಮಾಡಿ"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ಅತಿಥಿ ಮೋಡ್‌ನಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ನಿರ್ಗಮಿಸುವಾಗ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಯನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ನಿರ್ಗಮಿಸುವಾಗ ನಿಮ್ಮ ಚಟುವಟಿಕೆಯನ್ನು ನೀವು ಉಳಿಸಬಹುದು ಅಥವಾ ಅಳಿಸಬಹುದು"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ಸೆಶನ್ ಚಟುವಟಿಕೆಯನ್ನು ಈಗ ಅಳಿಸಲು ರೀಸೆಟ್ ಮಾಡಿ ಅಥವಾ ನಿರ್ಗಮಿಸುವಾಗ ನೀವು ಚಟುವಟಿಕೆಯನ್ನು ಉಳಿಸಬಹುದು ಅಥವಾ ಅಳಿಸಬಹುದು"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ಫೋಟೋ ಆಯ್ಕೆಮಾಡಿ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ನೀವು <xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿದರೆ ಅಥವಾ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿದರೆ, ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪ್ರಸಾರವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿ"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ಔಟ್‌ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ಮುನ್ನೋಟದ ಬ್ಯಾಕ್ ಆ್ಯನಿಮೇಶನ್‌ಗಳು"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ಮುನ್ನೋಟದ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್‌ಗಾಗಿ ಸಿಸ್ಟಂ ಆ್ಯನಿಮೇಶನ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ಮುನ್ನೋಟದ ಗೆಸ್ಚರ್ ಆ್ಯನಿಮೇಶನ್‌ಗಾಗಿ ಸಿಸ್ಟಂ ಆ್ಯನಿಮೇಶನ್‌ಗಳನ್ನು ಈ ಸೆಟ್ಟಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸುತ್ತವೆ. ಇದನ್ನು ಮಾಡಲು, ಪ್ರತಿ ಆ್ಯಪ್‌ನ ಮ್ಯಾನಿಫೆಸ್ಟ್ ಫೈಲ್‌ನಲ್ಲಿರುವ enableOnBackInvokedCallback ಪ್ಯಾರಾಮೀಟರ್ ಅನ್ನು ಸರಿ ಎಂದು ಹೊಂದಿಸಬೇಕು."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 4fb2385aa655..e946c71ddad8 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"재설정"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"삭제"</string>
<string name="guest_resetting" msgid="7822120170191509566">"게스트 재설정 중…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"게스트 세션을 재설정하시겠습니까?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"새로운 게스트 세션이 시작되고 기존 세션의 모든 앱과 데이터가 삭제됩니다."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"게스트 모드를 종료하시겠습니까?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"현재 게스트 세션의 앱과 데이터가 삭제됩니다."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"종료"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"게스트 활동을 저장하시겠습니까?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"기존 세션의 활동을 저장하거나 모든 앱과 데이터를 삭제할 수 있습니다."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"삭제"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"저장"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"게스트 모드 종료"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"게스트 세션 재설정"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"게스트 종료"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"종료하면 모든 활동이 삭제됩니다."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"종료 시 활동을 저장하거나 삭제할 수 있습니다."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"지금 재설정하여 활동 세션을 삭제하거나 종료 시 활동을 저장 또는 삭제할 수 있습니다."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"사진 찍기"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"이미지 선택"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"사진 선택"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 방송"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"출력 변경"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"예측된 뒤로 동작 애니메이션"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"예측된 뒤로 동작에 시스템 애니메이션을 사용하도록 설정합니다."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"이 설정은 예측된 동작 애니메이션에 시스템 애니메이션을 사용하도록 합니다. 매니페스트 파일에서 앱별 enableOnBackInvokedCallback을 True로 설정해야 합니다."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index b4f78170c548..02d03dbb8e71 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Баштапкы абалга келтирүү"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Өчүрүү"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Конок сеансы баштапкы абалга келтирилүүдө…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Конок сеансын баштапкы абалга келтиресизби?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Бул аракет жаңы конок сеансын баштап, учурдагы сеанстагы бардык колдонмолорду жана алардагы нерселерди жок кылат"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Конок режиминен чыгасызбы?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Бул учурдагы конок сеансындагы колдонмолорду жана алардагы нерселерди жок кылат"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Чыгуу"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Коноктун аракеттерин сактайсызбы?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Учурдагы сеанстагы аракеттерди сактап же бардык колдонмолорду жана алардагы нерселерди жок кылсаңыз болот"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Өчүрүү"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сактоо"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Конок режиминен чыгуу"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Конок сеансын кайра коюу"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Конок режиминен чыгуу"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Чыксаңыз, бардык аракеттер өчүрүлөт"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Чыгуудан мурун аракеттериңизди сактап же жок кылсаңыз болот"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанстагы аракеттерди азыр өчүрсөңүз болот же чыгып баратып өчүрүп же сактап коюңуз"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сүрөткө тартуу"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сүрөт тандаңыз"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Сүрөт тандаңыз"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарлоо"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Аудионун чыгуусун өзгөртүү"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Божомолдонгон анимациялар"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Божомолдоп билүү үчүн тутумдун анимацияларын иштетиңиз."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Бул параметр жаңсоо анимациясын божомолдоп билүү үчүн тутумдун анимацияларын иштетет. Ал үчүн манифест файлындагы enableOnBackInvokedCallback параметри ар бир колдонмо үчүн \"true\" деп коюлушу керек."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 44621372bff4..e1b2bdab1806 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -175,7 +175,7 @@
<string name="data_usage_ota" msgid="7984667793701597001">"ການອັບເດດລະບົບ"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"ການປ່ອຍສັນຍານຜ່ານ USB"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"ຮັອດສະປອດເຄື່ອນທີ່"</string>
- <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ການປ່ອຍສັນຍານດ້ວຍ Bluetooth"</string>
+ <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ປ່ອຍສັນຍານຜ່ານ Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"ການປ່ອຍສັນຍານ"</string>
<string name="tether_settings_title_all" msgid="8910259483383010470">"ການປ່ອຍສັນຍານ &amp; ຮັອດສະປອດເຄື່ອນທີ່"</string>
<string name="managed_user_title" msgid="449081789742645723">"ແອັບເຮັດວຽກທັງໝົດ"</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ຣີເຊັດ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ລຶບອອກ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ກຳລັງຣີເຊັດແຂກ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ຣີເຊັດເຊດຊັນຂອງແຂກບໍ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ນີ້ຈະເລີ່ມໄລຍະເວລາຂອງແຂກໃໝ່ ແລະ ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດອອກຈາກເຊດຊັນປັດຈຸບັນ"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ອອກຈາກໂໝດແຂກບໍ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ນີ້ຈະລຶບແອັບ ແລະ ຂໍ້ມູນອອກຈາກເຊດຊັນແຂກປັດຈຸບັນ"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ອອກ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ບັນທຶກການເຄື່ອນໄຫວແຂກບໍ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"ທ່ານສາມາດບັນທຶກການເຄື່ອນໄຫວຈາກເຊດຊັນປັດຈຸບັນ ຫຼື ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດໄດ້"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ລຶບ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ບັນທຶກ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ອອກຈາກໂໝດແຂກ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ຣີເຊັດເຊດຊັນຂອງແຂກ"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ອອກຈາກແຂກ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ການເຄື່ອນໄຫວທັງໝົດຈະຖືກລຶບໃນຕອນອອກ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ທ່ານສາມາດບັນທຶກ ຫຼື ລຶບການເຄື່ອນໄຫວຂອງທ່ານໃນຕອນອອກໄດ້"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ຣີເຊັດເພື່ອລຶບການເຄື່ອນໄຫວເຊດຊັນຕອນນີ້ ຫຼື ທ່ານສາມາດບັນທຶກ ຫຼື ລຶບການເຄື່ອນໄຫວໃນຕອນອອກໄດ້"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ຖ່າຍຮູບ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ເລືອກຮູບ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ເລືອກຮູບ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"ອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ປ່ຽນເອົ້າພຸດ"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ອະນິເມຊັນກັບຫຼັງແບບຄາດເດົາ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ເປີດການນຳໃຊ້ອະນິເມຊັນລະບົບສຳລັບການກັບຫຼັງແບບຄາດເດົາ."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ການຕັ້ງຄ່ານີ້ຈະເປີດການນຳໃຊ້ອະນິເມຊັນລະບົບສຳລັບອະນິເມຊັນທ່າທາງແບບຄາດເດົາ. ມັນຕ້ອງໃຊ້ການຕັ້ງຄ່າຕໍ່ແອັບ enableOnBackInvokedCallback ເປັນ true ໃນໄຟລ໌ manifest."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b3866dced3e2..2aa026ad7426 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Nustatyti iš naujo"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Pašalinti"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Svečias nustatomas iš naujo…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Nustatyti svečio sesiją iš naujo?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Bus pradėta nauja svečio sesija ir iš esamos sesijos bus ištrintos visos programos ir duomenys"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Išeiti iš svečio režimo?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bus ištrintos esamos svečio sesijos programos ir duomenys"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Išeiti"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Išsaugoti svečio veiklą?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Galite išsaugoti esamos sesijos veiklą arba ištrinti visas programas ir duomenis"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Ištrinti"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Išsaugoti"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Išeiti iš svečio režimo"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Nustatyti svečio sesiją iš naujo"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Išeiti iš svečio režimo"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Išėjus iš režimo visa veikla bus ištrinta"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Išeidami galite išsaugoti arba ištrinti savo veiklą"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nustatykite iš naujo, jei norite ištrinti sesijos veiklą dabar, arba galite išeidami išsaugoti ar ištrinti veiklą"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pasirinkti nuotrauką"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transliuoti „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Keisti išvestį"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Numatomos grįžimo atgal gestų animacijos"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Įgalinkite sistemos animacijas, kad būtų galima naudoti numatomus grįžimo atgal gestus."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Šis nustatymas įgalina numatomų grįžimo atgal gestų sistemos animacijas. Aprašo faile programos lauką „enableOnBackInvokedCallback“ reikia nustatyti į vertę „true“."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 1fa6bc8ec1c0..f561c2863488 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Atiestatīt"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Noņemt"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Notiek viesa sesijas atiestatīšana…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vai atiestatīt viesa sesiju?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Tādējādi tiks sākta jauna viesa sesijas un visas pašreizējās sesijas lietotnes un dati tiks dzēsti"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Vai iziet no viesa režīma?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Tādējādi tiks dzēstas pašreizējās viesa sesijas lietotnes un dati."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Iziet"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vai saglabāt viesa darbības?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Varat saglabāt pašreizējās sesijas darbības vai dzēst visas lietotnes un datus"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Dzēst"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Saglabāt"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Iziet no viesa režīma"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Atiestatīt viesa sesiju"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Iziet no viesa režīma"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Izejot tiks dzēstas visas darbības"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Izejot varat saglabāt vai dzēst savas darbības"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Atiestatiet, lai tagad dzēstu sesijas darbības. Izejot varēsiet saglabāt vai dzēst darbības."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Atlasīt fotoattēlu"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraide"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Izvades maiņa"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animāciju prognozēšana pāriešanai atpakaļ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Iespējot sistēmas animācijas prognozētam žestam pāriešanai atpakaļ."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Šis iestatījums iespējo sistēmas animācijas prognozēto žestu animācijām. Lai to varētu izmantot, parametram “enableOnBackInvokedCallback” lietotnes manifesta failā jāiestata vērtība “true”."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 43fe5e4318cf..8add55ca55d3 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Ресетирај"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Отстрани"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Се ресетира гостинот…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Да се ресетира гостинската сесија?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Ова ќе започне нова гостинска сесија и ќе ги избрише сите апликации и податоци од тековната сесија"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Да се излезе од режим на гостин?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ова ќе ги избрише сите апликации и податоци од тековната гостинска сесија"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Излези"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Да се зачува активност на гостин?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Може да зачувате активност од тековната сесија или да ги избришете сите апликации и податоци"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Избриши"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Зачувај"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Излези од режим на гостин"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Ресетирај ја гостинската сесија"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Излези од режим на гостин"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Целата активност ќе се избрише при излегувањето"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Можете да ја зачувате или избришете вашата активност при излегувањето"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ресетирајте за да ја избришете активноста на сесијата сега или може да ја зачувате или избришете активноста при излегувањето"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Изберете фотографија"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ако емитувате на <xliff:g id="SWITCHAPP">%1$s</xliff:g> или го промените излезот, тековното емитување ќе запре"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Емитување на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Променете излез"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Предвидливи анимации отпозади"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Овозможете предвидливи системски анимации отпозади."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Поставкава ги овозможува системските анимации за предвидливи движења. Поставката треба да се постави на „точно“ преку апликација enableOnBackInvokedCallback во датотеката за манифест."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 64bf8f73a011..7a57a712107f 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"നീക്കം ചെയ്യുക"</string>
<string name="guest_resetting" msgid="7822120170191509566">"അതിഥിയെ റീസെറ്റ് ചെയ്യുന്നു…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"അതിഥി സെഷൻ റീസെറ്റ് ചെയ്യണോ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ഇത് പുതിയൊരു അതിഥി സെഷൻ ആരംഭിക്കുകയും നിലവിലെ സെഷനിൽ നിന്ന് എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കുകയും ചെയ്യും"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കണോ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"നിലവിലെ അതിഥി സെഷനിൽ നിന്ന് ആപ്പുകളും ഡാറ്റയും ഇത് ഇല്ലാതാക്കും"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"പുറത്തുകടക്കുക"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"അതിഥി ആക്‌റ്റിവിറ്റി സംരക്ഷിക്കണോ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"നിലവിലെ സെഷനിൽ നിന്നുള്ള ആക്‌റ്റിവിറ്റി സംരക്ഷിക്കാം അല്ലെങ്കിൽ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കാം"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ഇല്ലാതാക്കുക"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"സംരക്ഷിക്കുക"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"പുറത്തുകടക്കുക"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"അതിഥി സെഷൻ റീസെറ്റ് ചെയ്യുക"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"പുറത്തുകടക്കുമ്പോൾ എല്ലാ ആക്‌റ്റിവിറ്റിയും ഇല്ലാതാക്കും"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"പുറത്തുകടക്കുമ്പോൾ ആക്‌റ്റിവിറ്റി സംരക്ഷിക്കുകയോ ഇല്ലാതാക്കുകയോ ചെയ്യാം"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"സെഷൻ ആക്‌റ്റിവിറ്റി ഇപ്പോൾ ഇല്ലാതാക്കാൻ റീസെറ്റ് ചെയ്യുക അല്ലെങ്കിൽ പുറത്തുകടക്കുമ്പോൾ ആക്‌റ്റിവിറ്റി സംരക്ഷിക്കുകയോ ഇല്ലാതാക്കുകയോ ചെയ്യാം"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ഫോട്ടോ തിരഞ്ഞെടുക്കുക"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്‌കാസ്റ്റ് അവസാനിക്കും"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുക"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ഔട്ട്പുട്ട് മാറ്റുക"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"പ്രെഡിക്റ്റീവ് ബാക്ക് ആനിമേഷനുകൾ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"പ്രെഡിക്റ്റീവ് ബാക്കിനായി സിസ്റ്റം ആനിമേഷനുകൾ പ്രവർത്തനക്ഷമമാക്കുക."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ഈ ക്രമീകരണം പ്രെഡിക്റ്റീവ് ജെസ്ച്ചർ ആനിമേഷന് വേണ്ടി സിസ്റ്റം ആനിമേഷനുകളെ പ്രവർത്തനക്ഷമമാക്കുന്നു. ഇതിന് ഓരോ ആപ്പിലും enableOnBackInvokedCallback എന്നത് മാനിഫെസ്റ്റ് ഫയലിൽ ശരി എന്ന് സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 5dc88cd3637a..df95d45f9876 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Шинэчлэх"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Хасах"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Зочныг шинэчилж байна…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Зочны харилцан үйлдлийг шинэчлэх үү?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Энэ нь шинэ зочны харилцан үйлдэл эхлүүлж, одоогийн харилцан үйлдлээс бүх апп болон өгөгдлийг устгана"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Зочны горимоос гарах уу?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Энэ нь одоогийн зочны харилцан үйлдлээс аппууд болон өгөгдлийг устгана"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Гарах"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Зочны үйл ажиллагааг хадгалах уу?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Та одоогийн харилцан үйлдлээс үйл ажиллагаа хадгалах эсвэл бүх апп, өгөгдлийг устгаж болно"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Устгах"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Хадгалах"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Зочны горимоос гарах"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Зочны харилцан үйлдлийг шинэчлэх"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Зочны горимоос гарах"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Бүх үйл ажиллагааг гарах үед устгана"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Та гарахдаа үйл ажиллагаагаа хадгалах эсвэл устгах боломжтой"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Харилцан үйлдлийн үйл ажиллагааг одоо устгахын тулд шинэчлэх эсвэл та гарахдаа үйл ажиллагааг хадгалах, устгах боломжтой"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Зураг сонгох"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлэх"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Гаралтыг өөрчлөх"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Таамаглах боломжтой буцаах анимаци"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Таамаглах боломжтой буцаах зангаанд системийн анимацийг идэвхжүүлнэ үү."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Энэ тохиргоо нь таамаглах боломжтой зангааны анимацид системийн анимацийг идэвхжүүлнэ. Үүнд апп бүрд тодорхойлогч файлл enableOnBackInvokedCallback-г үнэн болгож тохируулахыг шаардана."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 45bc5b8011e0..25113d246947 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -31,7 +31,7 @@
<item msgid="7852381437933824454">"डिस्कनेक्ट करत आहे..."</item>
<item msgid="5046795712175415059">"डिस्कनेक्ट केले"</item>
<item msgid="2473654476624070462">"अयशस्वी"</item>
- <item msgid="9146847076036105115">"ब्लॉक केले"</item>
+ <item msgid="9146847076036105115">"अवरोधित"</item>
<item msgid="4543924085816294893">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
</string-array>
<string-array name="wifi_status_with_ssid">
@@ -45,7 +45,7 @@
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वरून डिस्कनेक्ट करत आहे…"</item>
<item msgid="699832486578171722">"डिस्कनेक्ट केले"</item>
<item msgid="522383512264986901">"अयशस्वी"</item>
- <item msgid="3602596701217484364">"ब्लॉक केले"</item>
+ <item msgid="3602596701217484364">"अवरोधित"</item>
<item msgid="1999413958589971747">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
</string-array>
<string-array name="hdcp_checking_titles">
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 1f89b8ff0892..e7305a79e640 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"रीसेट करा"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"काढून टाका"</string>
<string name="guest_resetting" msgid="7822120170191509566">"अतिथीला रीसेट करत आहे…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"अतिथी सत्र रीसेट करायचे का?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"हे नवीन अतिथी सत्र सुरू करेल आणि सध्याच्या सत्रातील सर्व अ‍ॅप्स व डेटा हटवेल"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"अतिथी मोडमधून बाहेर पडायचे का?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"हे सध्याच्या अतिथी सत्रातील अ‍ॅप्स आणि डेटा हटवेल"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"बाहेर पडा"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"अतिथी अ‍ॅक्टिव्हिटी सेव्ह करायची का?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"सध्याच्या सत्रातील अ‍ॅक्टिव्हिटी सेव्ह करू किंवा सर्व अ‍ॅप्स व डेटा हटवू शकता"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"हटवा"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"सेव्ह करा"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"अतिथी मोडमधून बाहेर पडा"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"अतिथी सत्र रीसेट करा"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"अतिथी मोडमधून बाहेर पडा"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"बाहेर पडल्यावर सर्व अ‍ॅक्टिव्हिटी हटवली जाईल"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"बाहेर पडल्यावर तुमची अ‍ॅक्टिव्हिटी सेव्ह करू किंवा हटवू शकता"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"सत्र अ‍ॅक्टिव्हिटी आता हटवण्यासाठी रीसेट करा किंवा तुम्ही बाहेर पडल्यावर अ‍ॅक्टिव्हिटी सेव्ह करू अथवा हटवू शकता"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"फोटो निवडा"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण करा"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"आउटपूट बदला"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"पूर्वानुमानित मागे जाण्याचे अ‍ॅनिमेशन"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"पूर्वानुमानित मागे जाण्यासाठीचे सिस्टीम अ‍ॅनिमेशन सुरू करा."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"हे सेटिंग पूर्वानुमानित जेश्चर ॲनिमेशनसाठी सिस्टीम ॲनिमेशन सुरू करते. यासाठी मॅनिफेस्ट फाइलमध्ये प्रति ॲप enableOnBackInvokedCallback सत्य वर सेट करणे आवश्यक आहे."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 2034af25b130..a9eee9f2151f 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Tetapkan semula"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Alih keluar"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Menetapkan semula tetamu…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Tetapkan semula sesi tetamu?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Tindakan ini akan memulakan sesi tetamu baharu dan memadamkan semua apl dan data daripada sesi semasa"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Keluar daripada mod tetamu?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Tindakan ini akan memadamkan apl dan data daripada sesi tetamu semasa"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Keluar"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Simpan aktiviti tetamu?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Anda boleh menyimpan aktiviti daripada sesi semasa atau memadamkan semua apl dan data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Padam"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Simpan"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Keluar daripada mod tetamu"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Tetapkan semula sesi tetamu"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Keluar mod tetamu"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Semua aktiviti akan dipadamkan semasa keluar"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Aktiviti anda boleh disimpan atau dipadam semasa keluar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Tetapkan semula sesi untuk memadamkan aktiviti sesi sekarang atau anda boleh menyimpan atau memadamkan aktiviti semasa keluar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih imej"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Tukar output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animasi kembali ramalan"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Dayakan animasi sistem untuk kembali ramalan."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Tetapan ini mendayakan animasi sistem untuk animasi gerak isyarat ramalan. Animasi sistem memerlukan tetapan enableOnBackInvokedCallback untuk setiap apl kepada benar dalam fail manifes."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2514eff82333..adb52b83363e 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -448,7 +448,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&amp;lt&lt;/li&gt; &lt;li&gt;&amp;nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း&lt;/li&gt; &lt;/ol&gt;"</string>
+ <!-- syntax error in translation for accessibility_display_daltonizer_preference_subtitle (1522101114585266455) org.xmlpull.v1.XmlPullParserException: expected: /string read: li (position:END_TAG </li>@1:326 in <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&lt;/li&gt; &lt;li&gt;&amp;nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</string>
+) -->
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -598,6 +599,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ပြင်ဆင်သတ်မှတ်ရန်"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ဖယ်ရှားရန်"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်နေသည်…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ဧည့်သည် စက်ရှင် ပြင်ဆင်သတ်မှတ်မလား။"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"၎င်းသည် ဧည့်သည် စက်ရှင်အသစ်ကို စတင်မည်ဖြစ်ပြီး လက်ရှိစက်ရှင်မှ အက်ပ်နှင့် ဒေတာအားလုံးကို ဖျက်ပါမည်"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ဧည့်သည်မုဒ်မှ ထွက်မလား။"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"၎င်းသည် လက်ရှိဧည့်သည် စက်ရှင်မှ အက်ပ်နှင့် ဒေတာအားလုံးကို ဖျက်လိုက်ပါမည်"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ထွက်ရန်"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ဧည့်သည်လုပ်ဆောင်ချက် သိမ်းမလား။"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"လက်ရှိစက်ရှင်မှ လုပ်ဆောင်ချက် သိမ်းနိုင်သည် (သို့) အက်ပ်နှင့် ဒေတာအားလုံး ဖျက်နိုင်သည်"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ဖျက်ရန်"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"သိမ်းရန်"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ဧည့်သည်မုဒ်မှ ထွက်ရန်"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ဧည့်သည် စက်ရှင် ပြင်ဆင်သတ်မှတ်ရန်"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ဧည့်သည့်မှ ထွက်ရန်"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ထွက်သည့်အခါ လုပ်ဆောင်ချက်အားလုံးကို ဖျက်လိုက်မည်"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ထွက်သည့်အခါ လုပ်ဆောင်ချက်ကို သိမ်းနိုင် (သို့) ဖျက်နိုင်သည်"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"စက်ရှင်လုပ်ဆောင်ချက်ကို ယခုဖျက်ရန် ပြင်ဆင်သတ်မှတ်နိုင်သည် (သို့) ထွက်သည့်အခါ သိမ်းနိုင်၊ ဖျက်နိုင်သည်"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ဓာတ်ပုံရွေးရန်"</string>
@@ -656,7 +672,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ထုတ်လွှင့်ခြင်း"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"အထွက်ကို ပြောင်းခြင်း"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"နောက်ခလုတ်၏ ရှေ့ပြေးလှုပ်ရှားသက်ဝင်ပုံ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"နောက်ခလုတ်ရှေ့ပြေးအတွက် စနစ်လှုပ်ရှားသက်ဝင်ပုံများကို ဖွင့်ပါသည်။"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ဤဆက်တင်သည် လက်ဟန် ရှေ့ပြေးလှုပ်ရှားသက်ဝင်ပုံအတွက် စနစ်လှုပ်ရှားသက်ဝင်ပုံများကို ဖွင့်ပါသည်။ အက်ပ်တစ်ခုစီ၏ ဆက်တင်အတွက် enableOnBackInvokedCallback ကို မန်နီးဖက်စ် (manifest) ဖိုင်၌ ဖွင့်ထားရန်လိုအပ်သည်။"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 2f0b46f08261..d1aab87a0575 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Tilbakestill"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Fjern"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Tilbakestiller gjesten …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vil du tilbakestille gjesteøkten?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Dette starter en ny gjesteøkt og sletter alle apper og data fra den gjeldende økten"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Vil du avslutte gjestemodus?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Dette sletter apper og data fra den gjeldende gjesteøkten"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Avslutt"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vil du lagre gjesteaktivitet?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Du kan lagre aktivitet fra den gjeldende økten eller slette alle apper og data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Slett"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Lagre"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Avslutt gjestemodus"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Tilbakestill gjesteøkten"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Avslutt gjesteøkten"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All aktivitet slettes når du avslutter"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan lagre eller slette aktiviteten når du avslutter"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Tilbakestill for å slette øktaktivitet nå, eller du kan lagre eller slette aktivitet når du avslutter"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Velg et bilde"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Kringkast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Endre utgang"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Tilbake-animasjoner med forslag"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Slå på systemanimasjoner for tilbakebevegelser med forslag."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Denne innstillingen slår på systemanimasjoner for bevegelsesanimasjoner med forslag. Den krever at enableOnBackInvokedCallback settes til sann i manifestfilen for hver app."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 34da9a7a5245..69c5da444f7b 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"रिसेट गर्नुहोस्"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"हटाउनुहोस्"</string>
<string name="guest_resetting" msgid="7822120170191509566">"अतिथिका रूपमा ब्राउज गर्ने सेसन रिसेट गरिँदै छ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"अतिथि सत्र रिसेट गर्ने हो?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"यसो गर्नाले नयाँ अतिथि सत्र सुरु हुने छ र हालको अतिथि सत्रका सबै एप तथा डेटा मेटिने छ"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"अतिथि मोडबाट बाहिरिने हो?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"यसो गर्नाले हालको अतिथि सत्रका एप तथा डेटा मेटिने छ"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"बाहिरिनुहोस्"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"अतिथि सत्रमा गरिएका क्रियाकलाप सेभ गर्ने हो?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"तपाईं हालको सत्रमा गरिएका क्रियाकलाप सेभ गर्न वा सबै एप तथा डेटा मेटाउन सक्नुहुन्छ"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"मेटाउनुहोस्"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"सेभ गर्नुहोस्"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"अतिथि मोडबाट बाहिरिनुहोस्"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"अतिथि सत्र रिसेट गर्नुहोस्"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"अतिथि मोडबाट बाहिरिनुहोस्"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"अतिथि मोडबाट बाहिरिँदा सबै क्रियाकलाप मेटाइने छ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"तपाईं अतिथि मोडबाट बाहिरिँदा आफ्ना क्रियाकलाप सेभ गर्ने वा मेटाउने विकल्प रोज्न सक्नुहुन्छ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"यो सत्रमा गरिएका क्रियाकलाप अहिले नै मेटाउन रिसेट गर्नुहोस्, अथवा तपाईं अतिथि मोडबाट बाहिरिँदा आफ्ना क्रियाकलाप सेभ गर्ने वा मेटाउने विकल्प रोज्न सक्नुहुन्छ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो खिच्नुहोस्"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कुनै फोटो छनौट गर्नुहोस्"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"फोटो चयन गर्नुहोस्"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुहोस्"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"आउटपुट परिवर्तन गर्नुहोस्"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"पूर्वानुमानयुक्त ब्याक एनिमेसनहरू"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"पूर्वानुमानयुक्त ब्याक एनिमेसनका हकमा सिस्टम एनिमेसनहरू लागू गर्नुहोस्।"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"यो सेटिङले पूर्वानुमानयुक्त जेस्चर एनिमेसनका हकमा सिस्टम एनिमेनसहरू लागू गर्छ। म्यानिफेस्ट फाइलमा हरेक एपका हकमा enableOnBackInvokedCallback सेट गरी TRUE बनाएपछि मात्र यो सेटिङ अन गर्न मिल्छ।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f250b604eff9..90fb2a89d63d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetten"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Verwijderen"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gast resetten…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Gastsessie resetten?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hierdoor wordt een nieuwe gastsessie gestart en worden alle apps en gegevens van de huidige sessie verwijderd"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Gastmodus sluiten?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Hierdoor worden apps en gegevens van de huidige gastsessie verwijderd"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sluiten"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Gastactiviteit opslaan?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Sla activiteit van de huidige sessie op of verwijder alle apps en gegevens"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Verwijderen"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Opslaan"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Gastmodus sluiten"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Gastsessie resetten"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Gastmodus verlaten"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Alle activiteit wordt na het afsluiten verwijderd"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Je kunt je activiteit bij afsluiten opslaan of verwijderen"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Voer een reset uit om de sessie-activiteit nu te verwijderen of verwijder of sla je activiteit op bij afsluiten"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Foto selecteren"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzenden"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Uitvoer wijzigen"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Voorspellende animaties voor gebaren voor terug"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Systeemanimaties aanzetten voor voorspellende animaties voor gebaren voor terug."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Met deze instelling zet je systeemanimaties aan voor voorspellende gebaaranimaties. Je moet enableOnBackInvokedCallback per app instellen op True in het manifestbestand."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index fa57c63e8ce9..2145a610cf6f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -491,7 +491,7 @@
<string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string>
- <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
+ <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
<string name="home" msgid="973834627243661438">"ସେଟିଂସ ହୋମ"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ରିସେଟ୍ କରନ୍ତୁ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ଅତିଥି ସେସନକୁ ରିସେଟ୍ କରାଯାଉଛି…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ଅତିଥି ସେସନକୁ ରିସେଟ କରିବେ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ଏହା ଏକ ନୂଆ ଅତିଥି ସେସନ ଆରମ୍ଭ କରିବ ଏବଂ ବର୍ତ୍ତମାନର ସେସନରୁ ସମସ୍ତ ଆପ୍ସ ଏବଂ ଡାଟାକୁ ଡିଲିଟ କରିବ"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ଅତିଥି ମୋଡରୁ ବାହାରି ଯିବେ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ଏହା ବର୍ତ୍ତମାନର ଅତିଥି ସେସନରୁ ଆପ୍ସ ଏବଂ ଡାଟାକୁ ଡିଲିଟ କରିବ"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ବାହାରି ଯାଆନ୍ତୁ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ଅତିଥି କାର୍ଯ୍ୟକଳାପ ସେଭ କରିବେ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"ଆପଣ ଏବେର ସେସନରୁ କାର୍ଯ୍ୟକଳାପକୁ ସେଭ କରିପାରିବେ ବା ସବୁ ଆପ୍ସ ଓ ଡାଟାକୁ ଡିଲିଟ କରିପାରିବେ"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ଡିଲିଟ କରନ୍ତୁ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ସେଭ କରନ୍ତୁ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ଅତିଥି ମୋଡରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ଅତିଥି ସେସନକୁ ରିସେଟ କରନ୍ତୁ"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ଅତିଥି ମୋଡରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ବାହାରିବା ସମୟରେ ସମସ୍ତ କାର୍ଯ୍ୟକଳାପକୁ ଡିଲିଟ କରାଯିବ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ବାହାରିବା ସମୟରେ ଆପଣଙ୍କର କାର୍ଯ୍ୟକଳାପକୁ ସେଭ ବା ଡିଲିଟ କରିପାରିବେ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ବର୍ତ୍ତମାନ ସେସନ କାର୍ଯ୍ୟକଳାପକୁ ଡିଲିଟ କରିବାକୁ ରିସେଟ କରନ୍ତୁ କିମ୍ବା ବାହାରିବା ସମୟରେ ଆପଣ କାର୍ଯ୍ୟକଳାପକୁ ସେଭ କିମ୍ବା ଡିଲିଟ କରିପାରିବେ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ଗୋଟିଏ ଫଟୋ ଉଠାନ୍ତୁ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ଏକ ଛବି ବାଛନ୍ତୁ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ଫଟୋ ବାଛନ୍ତୁ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତୁ"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ଆଉଟପୁଟ ବଦଳାନ୍ତୁ"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ପ୍ରେଡିକ୍ଟିଭ ବ୍ୟାକ ଆନିମେସନ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ପ୍ରେଡିକ୍ଟିଭ ବ୍ୟାକ ପାଇଁ ସିଷ୍ଟମ ଆନିମେସନଗୁଡ଼ିକୁ ସକ୍ଷମ କରନ୍ତୁ।"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ଏହି ସେଟିଂ ପ୍ରେଡିକ୍ଟିଭ ଜେଶ୍ଚର ଆନିମେସନ ପାଇଁ ସିଷ୍ଟମ ଆନିମେସନଗୁଡ଼ିକୁ ସକ୍ଷମ କରେ। ଏଥିପାଇଁ ମାନିଫେଷ୍ଟ ଫାଇଲରେ ପ୍ରତି-ଆପ enableOnBackInvokedCallbackକୁ \"ଠିକ\"ରେ ସେଟ କରିବା ଆବଶ୍ୟକ।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 90f2b0fddb9b..330beb612235 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ਰੀਸੈੱਟ ਕਰੋ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ਹਟਾਓ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ਮਹਿਮਾਨ ਨੂੰ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ਕੀ ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ਇਸ ਨਾਲ ਨਵਾਂ ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਸ਼ੁਰੂ ਹੋ ਜਾਵੇਗਾ ਅਤੇ ਮੌਜੂਦਾ ਸੈਸ਼ਨ ਦੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ਕੀ ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣਾ ਹੈ?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ਇਸ ਨਾਲ ਮੌਜੂਦਾ ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਦੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ਬਾਹਰ ਜਾਓ"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ਕੀ ਮਹਿਮਾਨ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰਨੀ ਹੈ?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"ਤੁਸੀਂ ਮੌਜੂਦਾ ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਸਕਦੇ ਹੋ ਜਾਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ਮਿਟਾਓ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"ਰੱਖਿਅਤ ਕਰੋ"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਾਰੀ ਸਰਗਰਮੀ ਮਿਟਾਈ ਜਾਵੇਗੀ"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਆਪਣੀ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਹੁਣੇ ਮਿਟਾਉਣ ਲਈ ਰੀਸੈੱਟ ਕਰੋ ਜਾਂ ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ਇੱਕ ਫ਼ੋਟੋ ਖਿੱਚੋ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ਕੋਈ ਚਿੱਤਰ ਚੁਣੋ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ਫ਼ੋਟੋ ਚੁਣੋ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰੋ"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ਆਊਟਪੁੱਟ ਬਦਲੋ"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ਪਿਛਲੇ ਐਨੀਮੇਸ਼ਨਾਂ ਦਾ ਪੂਰਵ-ਅਨੁਮਾਨ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ਪੂਰਵ-ਅਨੁਮਾਨ ਵਾਪਸੀ ਲਈ ਸਿਸਟਮ ਐਨੀਮੇਸ਼ਨਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ਇਹ ਸੈਟਿੰਗ ਪੂਰਵ-ਅਨੁਮਾਨ ਇਸ਼ਾਰਾ ਐਨੀਮੇਸ਼ਨ ਲਈ ਸਿਸਟਮ ਐਨੀਮੇਸ਼ਨਾਂ ਨੂੰ ਚਾਲੂ ਕਰਦੀ ਹੈ। ਮੈਨੀਫ਼ੈਸਟ ਫ਼ਾਈਲ ਵਿੱਚ enableOnBackInvokedCallback ਸੈਟਿੰਗ ਨੂੰ ਪ੍ਰਤੀ-ਐਪ \'ਸਹੀ\' \'ਤੇ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 1eb1b6c870b9..66ede0cd104d 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetuj"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Usuń"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetuję sesję gościa…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Zresetować sesję gościa?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Zostanie uruchomiona nowa sesja gościa. Wszystkie aplikacje i dane z obecnej sesji zostaną usunięte."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Zamknąć tryb gościa?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Wszystkie aplikacje i dane z obecnej sesji gościa zostaną usunięte."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Wyjdź"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Zapisać aktywność gościa?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Możesz zapisać aktywność z obecnej sesji lub usunąć wszystkie aplikacje i dane"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Usuń"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Zapisz"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Zamknij tryb gościa"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Zresetuj sesję gościa"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Zakończ tryb gościa"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Cała aktywność zostanie usunięta po zamknięciu"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Możesz zapisać lub usunąć swoją aktywność podczas zamykania."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Zresetuj, aby teraz usunąć aktywność z tej sesji. Możesz też ją zapisać lub usunąć podczas zamykania sesji."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Wybierz zdjęcie"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmisja aplikacji <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Zmień dane wyjściowe"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacje przewidywanego przejścia wstecz"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Włącz animacje systemowe dla przewidywanego przejścia wstecz."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"To ustawienie uruchamia animacje systemowe dla przewidywanych gestów. Wymaga ustawienia w pliku manifestu wartości true w polu enableOnBackInvokedCallback dla każdej aplikacji."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 8c3f1fad8211..fa3b4ae8943b 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -149,7 +149,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de ligações quando estiver conectado."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Redefinir"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remover"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Redefinindo visitante…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Redefinir Sessão de visitante?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Essa ação vai iniciar uma nova Sessão de visitante e excluir todos os apps e dados da sessão atual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Sair do modo visitante?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Essa ação vai excluir apps e dados da Sessão de visitante atual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sair"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Salvar a atividade do visitante?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Você pode salvar a atividade da sessão atual ou excluir todos os apps e dados"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Excluir"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Sair do modo visitante"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Redefinir Sessão de visitante"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo visitante"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Todas as atividades serão excluídas ao sair"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Você pode salvar ou excluir sua atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Redefina para excluir a atividade da sessão agora. Salve ou exclua a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Mudar saída"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animações de gestos \"Voltar\" preditivos"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ativar animações do sistema para gestos \"Voltar\" preditivos."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta configuração ativa animações do sistema para gestos preditivos. Ela requer que a política enableOnBackInvokedCallback por app seja definida como verdadeira no arquivo de manifesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index ab0da74cba10..07b0cf5619ba 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Repor"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remover"</string>
<string name="guest_resetting" msgid="7822120170191509566">"A repor o convidado…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Repor sessão de convidado?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Esta ação inicia uma nova sessão de convidado e elimina todas as apps e dados da sessão atual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Sair do modo convidado?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Esta ação elimina as apps e os dados da sessão de convidado atual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sair"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Guardar atividade de convidado?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Pode guardar a atividade da sessão atual ou eliminar todas as apps e dados"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Eliminar"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Guardar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Sair do modo convidado"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Repor sessão de convidado"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo de convidado"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toda a atividade é eliminada ao sair"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Pode guardar ou eliminar a sua atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Reponha para eliminar agora a atividade da sessão. Pode ainda guardar ou eliminar a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmita a app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Altere a saída"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animações de gestos para voltar preditivos"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ative as animações do sistema para gestos para voltar preditivos."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta definição ativa animações do sistema para a animação de gestos preditivos. Requer a definição do atributo enableOnBackInvokedCallback por app como verdadeiro no ficheiro de manifesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 8c3f1fad8211..fa3b4ae8943b 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -149,7 +149,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de ligações quando estiver conectado."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Redefinir"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Remover"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Redefinindo visitante…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Redefinir Sessão de visitante?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Essa ação vai iniciar uma nova Sessão de visitante e excluir todos os apps e dados da sessão atual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Sair do modo visitante?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Essa ação vai excluir apps e dados da Sessão de visitante atual"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sair"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Salvar a atividade do visitante?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Você pode salvar a atividade da sessão atual ou excluir todos os apps e dados"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Excluir"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvar"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Sair do modo visitante"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Redefinir Sessão de visitante"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Sair do modo visitante"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Todas as atividades serão excluídas ao sair"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Você pode salvar ou excluir sua atividade ao sair"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Redefina para excluir a atividade da sessão agora. Salve ou exclua a atividade ao sair"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selecionar foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Mudar saída"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animações de gestos \"Voltar\" preditivos"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ativar animações do sistema para gestos \"Voltar\" preditivos."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta configuração ativa animações do sistema para gestos preditivos. Ela requer que a política enableOnBackInvokedCallback por app seja definida como verdadeira no arquivo de manifesto."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 4f142a81f472..8c0cd1130c89 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetați"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Eliminați"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Se resetează invitatul…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Resetați sesiunea pentru invitați?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Astfel, va începe o nouă sesiune pentru invitați și se vor șterge toate aplicațiile și datele din sesiunea actuală"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Ieșiți din modul pentru invitați?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Se vor șterge toate aplicațiile și datele din sesiunea pentru invitați actuală"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Ieșiți"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Salvați activitatea invitatului?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Salvați activitatea din sesiunea actuală sau ștergeți aplicațiile și datele"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Ștergeți"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvați"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Ieșiți din modul pentru invitați"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Resetați sesiunea pentru invitați"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ieșiți din modul pentru invitați"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toate activitățile vor fi șterse la ieșire"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puteți să salvați sau să ștergeți activitatea la ieșire"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetați pentru a șterge acum activitatea din sesiune sau salvați ori ștergeți activitatea la ieșire"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selectați fotografia"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Dacă difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbați rezultatul, difuzarea actuală se va opri"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Schimbați rezultatul"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animații pentru gestul înapoi predictiv"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activați animațiile de sistem pentru gestul înapoi predictiv."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Această setare activează animațiile de sistem pentru animația gesturilor predictive. Necesită setarea valorii true în cazul atributului enableOnBackInvokedCallback pentru fiecare aplicație în fișierul manifest."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index d70e31a21c0b..d6821106bb2a 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Сбросить"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Удалить"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Сброс гостевого сеанса…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Сбросить гостевой сеанс?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"При этом начнется новый гостевой сеанс, а все данные и приложения предыдущего сеанса будут удалены."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Выйти из гостевого режима?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Все приложения и данные текущего гостевого сеанса будут удалены."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Выйти"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Сохранить историю сеанса?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Сохраните историю текущего сеанса или удалите данные и приложения."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Удалить"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сохранить"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Выйти из гостевого режима"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Сбросить гостевой сеанс"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Выйти из гостевого режима"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"История будет удалена сразу после выхода."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"При выходе вы можете сохранить или удалить историю."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Можно сбросить историю сеанса прямо сейчас, либо удалить или сохранить ее при выходе."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Выбрать фотографию"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Если вы начнете транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" или смените целевое устройство, текущая трансляция прервется."</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Транслировать на другое устройство"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Анимации подсказки для жеста \"Назад\""</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Включить системную анимацию подсказки для жеста \"Назад\"."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"С помощью этого параметра можно включить системные анимации подсказок для жестов. Для этого нужно установить значение true для enableOnBackInvokedCallback в файле манифеста приложения."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 217ba1de6812..50818384d22b 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"යළි සකසන්න"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ඉවත් කරන්න"</string>
<string name="guest_resetting" msgid="7822120170191509566">"අමුත්තා යළි සකසමින්…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"ආගන්තුක සැසිය යළි සකසන්නද?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"මෙය නව ආගන්තුක සැසියක් ආරම්භ කර වත්මන් සැසියෙන් සියලු යෙදුම් සහ දත්ත මකනු ඇත"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ආගන්තුක ප්‍රකාරයෙන් පිටවන්නද?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"මෙය වත්මන් ආගන්තුක සැසියෙන් යෙදුම් සහ දත්ත මකනු ඇත"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"පිටවන්න"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"ආගන්තුක ක්‍රියාකාරකම් සුරකින්නද?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"ඔබට වත්මන් සැසියෙන් ක්‍රියාකාරකම් සුරැකීමට හෝ සියලු යෙදුම් සහ දත්ත මැකීමට හැකිය"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"මකන්න"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"සුරකින්න"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ආගන්තුක ප්‍රකාරයෙන් පිටවන්න"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"ආගන්තුක සැසිය යළි සකසන්න"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"අමුත්තා පිටවීම"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"පිටවීමේදී සියලු ක්‍රියාකාරකම් මකනු ඇත"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ඔබට පිටවීමේදී ඔබගේ ක්‍රියාකාරකම් සුරැකීමට හෝ මැකීමට හැකිය"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"දැන් සැසි ක්‍රියාකාරකම් මැකීමට යළි සකසන්න, නැතහොත් ඔබට පිටවීමේදී ක්‍රියාකාරකම් සුරැකීමට හෝ මැකීමට හැකිය"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ඡායාරූපයක් ගන්න"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"රූපයක් තෝරන්න"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ඡායාරූපය තෝරන්න"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්‍රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"ප්‍රතිදානය වෙනස් කරන්න"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"පුරෝකථනමය පසු සජීවිකරණ"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"පුරෝකථනමය ආපසු සඳහා පද්ධති සජීවිකරණ සබල කරන්න."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"මෙම සැකසීම පුරෝකථනමය ඉංගිත සජීවිකරණය සඳහා පද්ධති සජීවිකරණ සබල කරයි. එයට මැනිෆෙස්ට් ගොනුව තුළ එක් යෙදුමකට enableOnBackInvokedCallback සත්‍ය ලෙස සැකසීම අවශ්‍ය වේ."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 51588e33a97e..e562b468841e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -451,7 +451,7 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Úprava farieb môže byť užitočná, keď chcete:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;zobrazovať farby presnejšie;&lt;/li&gt; &lt;li&gt;&amp;nbsp;odstrániť farby, aby ste sa mohli sústrediť.&lt;/li&gt; &lt;/ol&gt;"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ešte približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> – závisí to od intenzity využitia"</string>
<string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> – závisí to od intenzity využitia (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetovať"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Odstrániť"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Relácia hosťa sa resetuje…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Chcete resetovať reláciu hosťa?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Týmto sa spustí nová relácia hosťa a odstránia sa všetky aplikácie a údaje z aktuálnej relácie"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Chcete ukončiť režim pre hostí?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ukončí sa režim pre hostí a odstránia sa aplikácie a údaje z relácie hosťa"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Ukončiť"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Chcete uložiť aktivitu hosťa?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Môžte uložiť aktivitu aktuálnej relácie alebo odstrániť všetky aplikácie a údaje"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Odstrániť"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Uložiť"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Ukončiť režim pre hostí"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Resetovať reláciu hosťa"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ukončiť režim pre hostí"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Pri ukončení sa všetka aktivita odstráni"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Aktivitu môžete pri ukončení uložiť alebo odstrániť"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetovaním ihneď odstránite aktivitu relácie alebo ju uložte či odstráňte pri ukončení relácie"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Vybrať fotku"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ak vysielate aplikáciu <xliff:g id="SWITCHAPP">%1$s</xliff:g> alebo zmeníte výstup, aktuálne vysielanie bude zastavené"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Vysielanie aplikácie <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Zmena výstupu"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Prediktívne animácie gesta Späť"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Povoľte animácie v systéme pre prediktívne gesto Späť"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Toto nastavenie povoľuje animácie v systéme na účely prediktívnej animácie gest. Vyžaduje nastavenie povolenia enableOnBackInvokedCallback na pravdu v súbore manifestu konkrétnej aplikácie."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index d1c355849fe5..9570f961b10a 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Ponastavi"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Odstrani"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Ponastavljanje gosta …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Želite ponastaviti sejo gosta?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"S tem boste začeli novo sejo gosta ter izbrisali vse aplikacije in podatke v trenutni seji."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Želite zapreti način za goste?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"S tem boste izbrisali aplikacije in podatke v trenutni seji gosta."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Zapri"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Želite shraniti dejavnost gosta?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Lahko shranite dejavnost v trenutni seji ali izbrišete vse aplikacije in podatke."</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Shrani"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Zapri način za goste"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Ponastavi sejo gosta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Zapri sejo gosta"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Ko zaprete način za goste, bo vsa dejavnost izbrisana."</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Ob zaprtju načina lahko shranite ali izbrišete dejavnost."</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ponastavite za izbris dejavnosti v seji zdaj, lahko pa jo shranite ali izbrišete, ko zaprete način za goste."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Izbira fotografije"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Oddajaj aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Sprememba izhoda"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacije poteze za nazaj s predvidevanjem"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Omogoči sistemske animacije za potezo za nazaj s predvidevanjem."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ta nastavitev omogoča sistemske animacije za animacijo poteze s predvidevanjem. V datoteki manifesta mora biti parameter »enableOnBackInvokedCallback« za posamezno aplikacijo nastavljen na »true«."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b5dfc5f43238..ee357bcf7946 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Rivendos"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Hiq"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Vizitori po rivendoset…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Të rivendoset sesioni për vizitorë?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Kjo do të fillojë një sesion të ri për vizitorë dhe do të fshijë të gjitha aplikacionet dhe të dhënat nga sesioni aktual"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Të hiqet modaliteti \"vizitor\"?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Kjo do të fshijë aplikacionet dhe të dhënat nga sesioni aktual për vizitorë"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Dil"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Të ruhet aktiviteti i vizitorit?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Ruaj aktivitetin nga sesioni aktual ose fshi të gjitha aplikacionet e të dhënat"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Fshi"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Ruaj"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Dil nga modaliteti \"vizitor\""</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Rivendos sesionin për vizitorë"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Dil nga modaliteti \"vizitor\""</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Të gjitha aktivitetet do të fshihen kur të dalësh"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Mund ta ruash ose ta fshish aktivitetin tënd kur të dalësh"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Rivendose për të fshirë aktivitetin e sesionit tani ose mund ta ruash ose ta fshish aktivitetin kur të dalësh"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Bëj një fotografi"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Zgjidh një imazh"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Zgjidh një fotografi"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Nëse transmeton <xliff:g id="SWITCHAPP">%1$s</xliff:g> ose ndryshon daljen, transmetimi yt aktual do të ndalojë"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Transmeto <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Ndrysho daljen"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animacionet për gjestin e parashikuar të kthimit prapa"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktivizo animacionet e sistemit për gjestin e parashikuar të kthimit prapa."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ky cilësim aktivizon animacionet e sistemit për animacionin e gjestit të parashikuar. Ai kërkon që enableOnBackInvokedCallback për aplikacionin të jetë caktuar si i vërtetë në skedarin e manifestit."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 4d8a11f68389..3937bcd0c09d 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Ресетуј"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Уклони"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Сесија госта се ресетује…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Желите да ресетујете сесију госта?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Тиме ћете покренути нову сесију госта и избрисати све апликације и податке из актуелне сесије"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Изаћи ћете из режима госта?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Тиме ћете избрисати све апликације и податке из актуелне сесије госта"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Изађи"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Сачуваћете активности госта?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Сачувајте активности из актуелне сесије или избришите све апликације и податке"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Избриши"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сачувај"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Изађи из режима госта"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Ресетуј сесију госта"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Изађи из режима госта"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Све активности ће бити избрисане при излазу"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Можете да сачувате или избришете активности при излазу"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ресетујете за брисање активности сесије, или сачувајте или избришите активности при излазу"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Изаберите слику"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ако емитујете апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените излаз, актуелно емитовање ће се зауставити"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Емитујте апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Промените излаз"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Анимације за покрет повратка са предвиђањем"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Омогућите анимације система за покрет повратка са предвиђањем."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ово подешавање омогућава анимације система за покрет повратка са предвиђањем. Захтева подешавање дозволе enableOnBackInvokedCallback по апликацији на true у фајлу манифеста."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 6e2ea780b24f..6f4a0c21322e 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Återställ"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ta bort"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gästsessionen återställs …"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Vill du återställa gästsessionen?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"En ny gästsession startas och alla appar och all data från den pågående sessionen raderas"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Vill du avsluta gästläget?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Appar och data från den pågående gästsessionen raderas"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Avsluta"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Vill du spara gästaktivitet?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Du kan spara aktivitet från den pågående sessionen eller radera appar och data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Radera"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Spara"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Avsluta gästläget"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Återställ gästsession"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Avsluta gästsession"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"All aktivitet raderas när du avslutar"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan spara eller radera aktivitet när du avslutar"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Återställ om du vill radera sessionsaktiviteten nu, eller spara eller radera aktivitet när du avslutar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Välj foto"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Sänd från <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Byt ljudutgång"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Förhandsanimationer för bakåtrörelser"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktivera systemanimationer som förhandsvisar bakåtrörelser."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Den här inställningen aktiverar systemanimationer som förhandsvisar vart rörelserna leder. Du måste ställa in enableOnBackInvokedCallback som sant per app i manifestfilen."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 36509e9a63ab..53270e067416 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Badilisha"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ondoa"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Inabadilisha kipindi cha mgeni…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Ungependa kuweka upya kipindi cha mgeni?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hii itaanzisha upya kipindi cha mgeni na kufuta programu na data yote kwenye kipindi cha sasa"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Utafunga matumizi ya wageni?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Hatua hii itafuta programu na data kutoka kwenye kipindi cha mgeni cha sasa"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Funga"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Utahifadhi shughuli za mgeni?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Unaweza kuhifadhi shughuli kutoka kipindi cha sasa au kufuta programu na data yote"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Futa"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Hifadhi"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Funga matumizi ya wageni"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Weka upya kipindi cha mgeni"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Funga utumiaji wa mgeni"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Shughuli zote zitafutwa wakati wa kufunga"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Unaweza kuhifadhi au kufuta shughuli zako wakati wa kufunga"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Weka upya ili ufute shughuli za kipindi sasa au unaweza kuhifadhi au kufuta shughuli wakati wa kufunga"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Piga picha"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chagua picha"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Chagua picha"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Ikiwa unatangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g> au unabadilisha maudhui, tangazo lako la sasa litasimamishwa"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Tangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Badilisha maudhui"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Uhuishaji wa utabiri wa kurudi nyuma"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Ruhusu uhuishaji wa mfumo wa utabiri wa kurudi nyuma."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Mipangilio hii inaruhusu uhuishaji wa mfumo wa uhuishaji wa utabiri wa ishara. Inahitaji kuweka mipangilio kwa kila programu enableOnBackInvokedCallback kuwa true katika faili ya maelezo."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 6d4c57955b2f..b2fccf86c1cd 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"மீட்டமை"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"அகற்று"</string>
<string name="guest_resetting" msgid="7822120170191509566">"கெஸ்ட்டை மீட்டமைக்கிறது…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"கெஸ்ட் அமர்வை ரீசெட் செய்யவா?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"புதிய கெஸ்ட் அமர்வு தொடங்கப்படும், மேலும் தற்போதைய கெஸ்ட் அமர்வின் ஆப்ஸ் மற்றும் தரவு அனைத்தும் நீக்கப்படும்"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"கெஸ்ட் முறையிலிருந்து வெளியேறவா?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"தற்போதைய கெஸ்ட் அமர்வின் ஆப்ஸ் மற்றும் தரவு அனைத்தும் நீக்கப்படும்"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"வெளியேறு"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"கெஸ்ட் செயல்பாடுகளைச் சேமிக்கவா?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"தற்போதைய அமர்வின் செயல்பாடுகளைச் சேமிக்கலாம் அல்லது ஆப்ஸையும் தரவையும் நீக்கலாம்"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"நீக்கு"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"சேமி"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"கெஸ்ட் பயன்முறையிலிருந்து வெளியேறு"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"கெஸ்ட் அமர்வை ரீசெட் செய்"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"கெஸ்ட் பயன்முறையிலிருந்து வெளியேறு"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"வெளியேறியவுடன் அனைத்துச் செயல்பாடுகளும் நீக்கப்படும்"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"வெளியேறும்போது செயல்பாடுகளைச் சேமிக்கலாம் அல்லது நீக்கலாம்"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"அமர்வின் செயல்பாடுகளை இப்போதே நீக்க ரீசெட் செய்யவும் அல்லது வெளியேறும்போது செயல்பாடுகளைச் சேமிக்கலாம் அல்லது நீக்கலாம்"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"படமெடுங்கள்"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"படத்தைத் தேர்வுசெய்யுங்கள்"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"படத்தைத் தேர்ந்தெடுங்கள்"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பு"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"அவுட்புட்டை மாற்று"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"கணிக்கக்கூடிய பின்செல் சைகைக்கான அனிமேஷன்கள்"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"கணிக்கக்கூடிய பின்செல் சைகைக்காகச் சிஸ்டம் அனிமேஷன்களை இயக்கும்."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"கணிக்கக்கூடிய சைகைக்கான அனிமேஷனுக்காக இந்த அமைப்பு சிஸ்டம் அனிமேஷன்களை இயக்கும். மெனிஃபெஸ்ட் ஃபைலில் ஒவ்வொரு ஆப்ஸுக்கும் enableOnBackInvokedCallbackகை \'சரி\' என அமைக்க வேண்டும்."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 5e6fa8e24b92..2b36e5e8ea57 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"రీసెట్ చేయండి"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"తీసివేయండి"</string>
<string name="guest_resetting" msgid="7822120170191509566">"గెస్ట్ సెషన్‌ను రీసెట్ చేస్తోంది…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"గెస్ట్ సెషన్‌ను రీసెట్ చేయాలా?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ఇది కొత్త గెస్ట్ సెషన్‌ను ప్రారంభిస్తుంది, ప్రస్తుత సెషన్ నుండి అన్ని యాప్‌లు, డేటాను తొలగిస్తుంది."</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"గెస్ట్ మోడ్ నిష్క్రమించాలా?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"ఇది ప్రస్తుత గెస్ట్ సెషన్ నుండి యాప్‌లను వాటితో పాటు డేటాను తొలగిస్తుంది"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"నిష్క్రమించండి"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"గెస్ట్ యాక్టివిటీని సేవ్ చేయాలా?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"మీరు సెషన్ నుండి యాక్టివిటీని సేవ్ చేయవచ్చు, అన్ని యాప్‌లు, డేటాను తొలగించవచ్చు"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"తొలగించండి"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"సేవ్ చేయండి"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"గెస్ట్ మోడ్ నుండి వైదొలగండి"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"గెస్ట్ సెషన్‌ను రీసెట్ చేయండి"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"గెస్ట్ మోడ్ నుండి నిష్క్రమించండి"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"నిష్క్రమణ సమయంలో మొత్తం యాక్టివిటీ తొలగించబడుతుంది"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"మీ నిష్క్రమణలో, యాక్టివిటీని సేవ్ చేయవచ్చు లేదా తొలగించవచ్చు"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"సెషన్ యాక్టివిటీని తొలగించడానికి ఇప్పుడే రీసెట్ చేయండి లేదా మీరు నిష్క్రమించేటప్పుడు యాక్టివిటీని సేవ్ చేయవచ్చు లేదా తొలగించవచ్చు"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ఇమేజ్‌ను ఎంచుకోండి"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ఫోటోను ఎంచుకోండి"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్‌పుట్‌ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేయండి"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"అవుట్‌పుట్‌ను మార్చండి"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"ఊహించదగిన బ్యాక్ యానిమేషన్‌లు"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"ఊహించదగిన బ్యాక్ యానిమేషన్‌ల కోసం సిస్టమ్ యానిమేషన్‌లను ఎనేబుల్ చేయండి."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"ఊహించదగిన సంజ్ఞ యానిమేషన్ కోసం ఈ సెట్టింగ్ సిస్టమ్ యానిమేషన్‌లను ఎనేబుల్ చేస్తుంది. దీనికి మ్యానిఫెస్ట్ ఫైల్‌లో ఒక్కో యాప్‌లో enableOnBackInvokedCallback సెట్టింగ్‌ను ఒప్పునకు సెట్ చేయవలసి ఉంటుంది."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 772a9795ba1d..db2d07badb7c 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"รีเซ็ต"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"นำออก"</string>
<string name="guest_resetting" msgid="7822120170191509566">"กำลังรีเซ็ตผู้เข้าร่วม…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"รีเซ็ตเซสชันผู้ใช้ชั่วคราวไหม"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"การดำเนินการนี้จะเริ่มเซสชันผู้ใช้ชั่วคราวใหม่ และจะลบแอปและข้อมูลทั้งหมดจากเซสชันปัจจุบัน"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"ออกจากโหมดผู้ใช้ชั่วคราวไหม"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"การดำเนินการนี้จะลบแอปและข้อมูลออกจากเซสชันผู้ใช้ชั่วคราวในปัจจุบัน"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"ออก"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"บันทึกกิจกรรมของผู้ใช้ชั่วคราวไหม"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"คุณสามารถบันทึกกิจกรรมจากเซสชันปัจจุบันหรือจะลบแอปและข้อมูลทั้งหมดก็ได้"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ลบ"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"บันทึก"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"ออกจากโหมดผู้ใช้ชั่วคราว"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"รีเซ็ตเซสชันผู้ใช้ชั่วคราว"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ออกจากโหมดผู้ใช้ชั่วคราว"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ระบบจะลบกิจกรรมทั้งหมดเมื่อออก"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"คุณสามารถบันทึกหรือลบกิจกรรมเมื่อออก"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"รีเซ็ตเพื่อลบกิจกรรมของเซสชันตอนนี้เลย หรือจะ​บันทึกหรือลบกิจกรรมเมื่อออกก็ได้"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"เลือกรูปภาพ"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"ออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"เปลี่ยนเอาต์พุต"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"การเคลื่อนไหวย้อนกลับแบบคาดเดา"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"เปิดใช้การเคลื่อนไหวของระบบสำหรับท่าทางสัมผัสย้อนกลับแบบคาดเดา"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"การตั้งค่านี้จะเปิดใช้การเคลื่อนไหวของระบบสำหรับการเคลื่อนไหวจากท่าทางสัมผัสแบบคาดเดา โดยต้องตั้งค่า enableOnBackInvokedCallback สำหรับแต่ละแอปให้เป็น \"จริง\" ในไฟล์ Manifest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index d9d4e3a1117b..fc17adeae5a4 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"I-reset"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Alisin"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Nire-reset ang bisita…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"I-reset ang session ng bisita?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Magsisimula ito ng bagong session ng bisita at made-delete ang lahat ng app at data mula sa kasalukuyang session"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Umalis sa guest mode?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Ide-delete nito ang mga app at data mula sa kasalukuyang session ng bisita"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Umalis"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"I-save ang aktibidad ng bisita?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Puwedeng i-save ang aktibidad ng session ngayon o i-delete lahat ng app at data"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"I-delete"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"I-save"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Umalis sa guest mode"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"I-reset ang session ng bisita"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Umalis sa pagiging bisita"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Made-delete ang lahat ng aktibidad kapag umalis"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puwede mong i-save o i-delete ang aktibidad pagkaalis"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Mag-reset para mag-delete ng aktibidad ng session ngayon, o puwede kang mag-save o mag-delete ng aktibidad pagkaalis"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pumili ng larawan"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"I-broadcast ang <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Baguhin ang output"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Mga animation ng predictive na pagbalik"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"I-enable ang mga animation ng system para sa predictive na pagbalik."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ine-enable ng setting na ito ang mga animation ng system para sa animation ng predictive na galaw. Kinakailangan nitong itakda sa true ang enableOnBackInvokedCallback sa bawat app sa manifest file."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index c47e8eea521a..49ffa6267280 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Sıfırla"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Kaldır"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Misafir oturumu sıfırlanıyor…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Misafir oturumu sıfırlansın mı?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Bu işlem, yeni bir misafir oturumu başlatarak mevcut oturumdaki tüm uygulamaları ve verileri siler"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Misafir modundan çıkılsın mı?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bu işlem mevcut misafir oturumundaki tüm uygulamaları ve verileri siler"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Çık"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Misafir etkinliği kaydedilsin mi?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Oturumdaki etkinliği kaydedebilir ya da tüm uygulama ve verileri silebilirsiniz"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Sil"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Kaydet"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Misafir modundan çık"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Misafir oturumunu sıfırla"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Misafir modundan çık"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Çıkış yapıldığında tüm etkinlikler silinir"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Etkinliklerinizi çıkarken kaydedebilir veya silebilirsiniz"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Oturum etkinliklerini silmek için sıfırlayabilir ya da çıkarken kaydedebilir veya silebilirsiniz"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotoğraf çek"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Resim seç"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Fotoğraf seç"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapın"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Çıkışı değiştirme"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Tahmine dayalı geri hareketi animasyonları"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Tahmine dayalı geri hareketi için sistem animasyonlarını etkinleştirin"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Bu ayar, tahmine dayalı hareket animasyonu için sistem animasyonlarını etkinleştirir. Her uygulamanın manifest dosyasında enableOnBackInvokedCallback\'in doğru değerine ayarlanması gerekir."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 00c2153cb4b8..5157af17dc44 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Скинути"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Вилучити"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Скидання сеансу в режимі \"Гість\"…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Скинути сеанс у режимі гостя?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Почнеться новий сеанс у режимі гостя, а всі додатки й дані з поточного сеансу буде видалено"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Вийти з режиму гостя?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Усі додатки й дані з поточного сеансу в режимі гостя буде видалено."</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Вийти"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Зберегти дії в режимі гостя?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Ви можете зберегти дії з поточного сеансу або видалити всі додатки й дані"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Видалити"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Зберегти"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Вийти з режиму гостя"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Скинути сеанс у режимі гостя"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Вийти з режиму гостя"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Під час виходу буде видалено історію всіх дій"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Під час виходу можна зберегти або видалити ваші дії"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Можна скинути історію сеансу просто зараз або видалити чи зберегти її під час виходу."</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Вибрати фотографію"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Змінити додаток для трансляції на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Змінити аудіовихід"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Анімації з підказками для жесту \"Назад\""</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Увімкніть системну анімацію з підказками для жесту \"Назад\"."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Якщо вибрати це налаштування, для жесту \"Назад\" відображатиметься анімація з підказками. У файлі маніфесту атрибуту enableOnBackInvokedCallback додатка потрібно присвоїти значення true."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 43dee94bd9a6..d5a27624f7ad 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ری سیٹ کریں"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"ہٹائیں"</string>
<string name="guest_resetting" msgid="7822120170191509566">"مہمان کو ری سیٹ کرنا…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"مہمان سیشن کو ری سیٹ کریں؟"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"اس سے ایک نیا مہمان سیشن شروع ہو گا اور موجودہ سیشن سے تمام ایپس اور ڈیٹا حذف ہو جائے گا"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"مہمان وضع سے باہر نکلیں؟"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"یہ موجودہ مہمان سیشن سے ایپس اور ڈیٹا کو حذف کر دے گا"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"باہر نکلیں"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"مہمان کی سرگرمی محفوظ کریں؟"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"آپ موجودہ سیشن سے سرگرمی کو محفوظ یا تمام ایپس اور ڈیٹا کو حذف کر سکتے ہیں"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"حذف کریں"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"محفوظ کریں"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"مہمان وضع سے باہر نکلیں"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"مہمان سیشن کو ری سیٹ کریں"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"مہمان وضع سے باہر نکلیں"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"باہر نکلنے پر تمام سرگرمیاں حذف کر دی جائیں گی"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"باہر نکلنے پر آپ اپنی سرگرمی کو محفوظ یا حذف کر سکتے ہیں"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"سیشن کی سرگرمی کو ابھی حذف کرنے کے لیے ری سیٹ کریں، یا باہر نکلنے پر آپ اپنی سرگرمی کو محفوظ یا حذف کر سکتے ہیں"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ایک تصویر لیں"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ایک تصویر منتخب کریں"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"تصویر منتخب کریں"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"اگر آپ <xliff:g id="SWITCHAPP">%1$s</xliff:g> براڈکاسٹ کرتے ہیں یا آؤٹ پٹ کو تبدیل کرتے ہیں تو آپ کا موجودہ براڈکاسٹ رک جائے گا"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> پر براڈکاسٹ کریں"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"آؤٹ پٹ تبدیل کریں"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"پیچھے جانے کے اشارے کی پیش گوئی والی اینیمیشنز"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"پیچھے جانے کے پیش گوئی والے اشارے کے لیے سسٹم اینیمیشنز فعال کریں۔"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏یہ ترتیب پیش گوئی والی اشارے کی اینیمیشن کے لیے سسٹم کی اینیمیشنز کو فعال کرتی ہے۔ اس کے لیے manifest فائل میں فی ایپ enableOnBackInvokedCallback کو درست پر سیٹ کرنے کی ضرورت ہے۔"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 22251c3c186d..3396f683ce35 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Tiklash"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Olib tashlash"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Mehmon seansi tiklanmoqda…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Mehmon seansi tiklansinmi?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Bunda yangi mehmon seansi ishga tushadi va joriy seans ilova va maʼlumotlari tozalanadi"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Mehmon rejimidan chiqasizmi?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bunda joriy mehmon seansidagi ilova va ularning maʼlumotlari tozalanadi"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Chiqish"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Mehmon faoliyati saqlansinmi?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Joriy seansdagi faoliyatni saqlash yoki barcha ilova va maʼlumotlarni oʻchirib tashlashingiz mumkin"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Oʻchirish"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Saqlash"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Mehmon rejimidan chiqish"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Mehmon seansini tiklash"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Mehmon rejimidan chiqish"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Chiqishda faolliklar tarixi tozalab tashlanadi"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Chiqish vaqtida faoliyatni saqlash yoki tozalash mumkin"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Faoliyat hozir tozalanib tiklanishi yoki chiqish vaqtida saqlanishi yoki tozalanishi mumkin"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Surat tanlash"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Agar <xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya qilsangiz yoki ovoz chiqishini oʻzgartirsangiz, joriy translatsiya toʻxtab qoladi"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Ovoz chiqishini oʻzgartirish"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Taxminiy qaytish animatsiyalari"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Taxminiy qaytish uchun tizim animatsiyalarini yoqish."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Bu sozlamalar taxminiy qaytish animatsiyalari uchun tizim animatsiyalarini faollashtiradi. Buning uchun har bir ilovaning manifest faylida enableOnBackInvokedCallback parametri “true” qiymatida boʻlishi lozim."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2be2b5c9bc15..9484fbaddd64 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Đặt lại"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Xoá"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Đang đặt lại phiên khách…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Đặt lại phiên khách?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Thao tác này sẽ bắt đầu một phiên khách mới và xoá mọi ứng dụng cũng như dữ liệu trong phiên hiện tại"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Thoát khỏi chế độ khách?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Thao tác này sẽ xoá các ứng dụng và dữ liệu trong phiên khách hiện tại"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Thoát"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Lưu hoạt động ở chế độ khách?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Bạn có thể lưu hoạt động trong phiên hiện tại hoặc xoá mọi ứng dụng và dữ liệu"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Xoá"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Lưu"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Thoát khỏi chế độ khách"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Đặt lại phiên khách"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Thoát khỏi chế độ khách"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Mọi hoạt động sẽ bị xoá khi thoát"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Bạn có thể lưu hoặc xoá hoạt động của mình khi thoát"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Đặt lại để xoá hoạt động trong phiên ngay bây giờ, hoặc bạn có thể lưu hoặc xoá hoạt động khi thoát"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Chụp ảnh"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chọn một hình ảnh"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Chọn ảnh"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Phát <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Thay đổi đầu ra"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Ảnh động vuốt ngược dự đoán"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Cho phép sử dụng ảnh động hệ thống cho chức năng vuốt ngược dự đoán."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Cài đặt này cho phép sử dụng ảnh động hệ thống cho ảnh động cử chỉ dự đoán. Nó yêu cầu cài đặt cho mỗi ứng dụng chuyển enableOnBackInvokedCallback thành lệnh true trong tệp kê khai."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index e5dd6a014ddc..04378ac3270b 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"重置"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"移除"</string>
<string name="guest_resetting" msgid="7822120170191509566">"正在重置访客会话…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"要重置访客会话吗?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"此操作会开始新的访客会话,并删除当前会话中的所有应用和数据"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"要退出访客模式吗?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"此操作会删除当前访客会话中的所有应用和数据"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"退出"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"要保存访客活动记录吗?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"您可以保存当前会话中的活动记录,也可以删除所有应用和数据"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"删除"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"保存"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"退出访客模式"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"重置访客会话"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"退出访客模式"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"退出时所有活动记录都将被删除"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"您可以在退出时保存或删除您的活动记录"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"请立即重置以删除会话活动记录;或者,您也可以在退出时保存或删除活动记录"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍摄照片"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"选择图片"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"选择照片"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"更改输出来源"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"预测性返回手势动画"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"启用系统动画作为预测性返回手势动画。"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"此设置将启用系统动画作为预测性手势动画。这要求在清单文件中将单个应用的 enableOnBackInvokedCallback 设为 true。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 282d05b595b8..ca2e69e10a81 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"重設"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"移除"</string>
<string name="guest_resetting" msgid="7822120170191509566">"正在重設訪客…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"要重設訪客工作階段嗎?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"此操作會開始新的訪客工作階段,並刪除目前工作階段的所有應用程式和資料"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"要結束訪客模式嗎?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"此操作會刪除目前訪客工作階段中的所有應用程式和資料"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"結束"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"要儲存訪客活動嗎?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"您可儲存目前工作階段中的活動或刪除所有應用程式和資料"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"刪除"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"儲存"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"結束訪客模式"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"重設訪客工作階段"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"結束訪客模式"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"結束時將會刪除所有活動"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"您可以在結束時儲存或刪除活動"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"重設可立即刪除工作階段活動,或者您可以在結束時儲存或刪除活動"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"揀相"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"變更輸出來源"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"預測返回手勢動畫"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"為預測返回手勢啟用系統動畫。"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"此設定會啟用系統動畫作為預測手勢動畫。這必須在資訊清單檔案中將個別應用程式的 enableOnBackInvokedCallback 設定為 true。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index e439ef5d6edf..8f6671cf3ca0 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"重設"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"移除"</string>
<string name="guest_resetting" msgid="7822120170191509566">"正在重設訪客…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"要重設訪客工作階段嗎?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"這麼做將開始新的訪客工作階段,並刪除目前工作階段中的所有應用程式和資料"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"要結束訪客模式嗎?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"這麼做將刪除目前訪客工作階段中的所有應用程式和資料"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"結束"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"要儲存訪客活動嗎?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"你可以儲存目前工作階段中的活動,也可以刪除所有應用程式和資料"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"刪除"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"儲存"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"結束訪客模式"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"重設訪客工作階段"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"結束訪客模式"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"結束時將刪除所有活動"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"你可以在結束時儲存或刪除活動"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"重設即可立即刪除工作階段活動,你也可以在結束時儲存或刪除活動"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"選取相片"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"變更輸出來源"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"預測返回操作動畫"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"為預測返回操作啟用系統動畫。"</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"這項設定會啟用系統動畫做為預測手勢動畫。這必須在資訊清單檔案中將個別應用程式的 enableOnBackInvokedCallback 設為 true。"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index ebc9cb7927ff..762484b9ea3b 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -598,6 +598,21 @@
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Setha kabusha"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Susa"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Ukusetha kabusha isimenywa…"</string>
+ <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Sesha kabusha isikhathi sesihambeli?"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Lokhu kuzoqala isikhathi sesihambeli esisha futhi kusule wonke ama-app nedatha kusuka esikhathini samanje"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Phuma kumodi yesihambeli?"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Lokhu kuzosula ama-app nedatha kusuka esikhathini sesihambeli samanje"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Phuma"</string>
+ <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Londoloza umsebenzi wesihambeli?"</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Ungalondoloza umsebenzi kusuka esikhathini samanje noma usule wonke ama-app nedatha"</string>
+ <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Sula"</string>
+ <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Londoloza"</string>
+ <string name="guest_exit_button" msgid="5774985819191803960">"Phuma kumodi yesivakashi"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"Setha kabusha isikhathi sesihambeli"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Phuma kusivakashi"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Wonke umsebenzi uzosulwa lapho uphuma"</string>
+ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Ungalondoloza noma usule umsebenzi wakho lapho uphuma"</string>
+ <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Setha kabusha ukuze usule umsebenzi wesikhathi manje, noma ungalondoloza noma usule umsebenzi lapho uphuma"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Khetha isithombe"</string>
@@ -656,7 +671,4 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Sakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Shintsha okuphumayo"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Ukubikezelwa kwasemuva kopopayi"</string>
- <string name="back_navigation_animation_summary" msgid="741292224121599456">"Nika amandla ukubikezela emuva kopopayi besistimu."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Leli sethingi livumela opopayi besistimu mayelana nokuthinta okubikezelwayo kopopayi. Idinga ukusetha i-app ngayinye ku-enableOnBackInvokedCallback ukuze iqinisekise ifayela le-manifest."</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 847f1dc541e8..f92cc8eda268 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1134,6 +1134,8 @@
<string name="battery_info_status_charging_slow">Charging slowly</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging wirelessly. -->
<string name="battery_info_status_charging_wireless">Charging wirelessly</string>
+ <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when the device is dock charging. -->
+ <string name="battery_info_status_charging_dock">Charging Dock</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_discharging">Not charging</string>
<!-- Battery Info screen. Value for a status item. A state which device is connected with any charger(e.g. USB, Adapter or Wireless) but not charging yet. Used for diagnostic info screens, precise translation isn't needed -->
@@ -1438,6 +1440,44 @@
<string name="guest_remove_guest_confirm_button">Remove</string>
<!-- Status message indicating the device is in the process of resetting the guest user. [CHAR_LIMIT=NONE] -->
<string name="guest_resetting">Resetting guest\u2026</string>
+ <!-- Dialog title on action reset and restart guest [CHAR LIMIT=60] -->
+ <string name="guest_reset_and_restart_dialog_title">Reset guest session?</string>
+ <!-- Dialog message on action reset and restart guest [CHAR LIMIT=160] -->
+ <string name="guest_reset_and_restart_dialog_message">This will start a new guest
+ session and delete all apps and data from the current session</string>
+ <!-- Dialog title on action exit guest (ephemeral guest) [CHAR LIMIT=32] -->
+ <string name="guest_exit_dialog_title">Exit guest mode?</string>
+ <!-- Dialog message on action exit guest (ephemeral guest) [CHAR LIMIT=80] -->
+ <string name="guest_exit_dialog_message">This will delete
+ apps and data from the current guest session</string>
+ <!-- Dialog button on action exit guest (ephemeral guest) [CHAR LIMIT=80] -->
+ <string name="guest_exit_dialog_button">Exit</string>
+ <!-- Dialog title on action exit guest (non-ephemeral guest) [CHAR LIMIT=32] -->
+ <string name="guest_exit_dialog_title_non_ephemeral">Save guest activity?</string>
+ <!-- Dialog message on action exit guest (non-ephemeral guest) [CHAR LIMIT=80] -->
+ <string name="guest_exit_dialog_message_non_ephemeral">You can save activity from
+ the current session or delete all apps and data</string>
+ <!-- Button on guest exit, clear data (non-ephemeral guest) [CHAR LIMIT=80] -->
+ <string name="guest_exit_clear_data_button">Delete</string>
+ <!-- Button on guest exit, save data (non-ephemeral guest) [CHAR LIMIT=80] -->
+ <string name="guest_exit_save_data_button">Save</string>
+ <!-- Label for button in confirmation dialog when exiting guest user [CHAR LIMIT=35] -->
+ <string name="guest_exit_button">Exit guest mode</string>
+ <!-- Label for button in confirmation dialog when resetting guest user [CHAR LIMIT=35] -->
+ <string name="guest_reset_button">Reset guest session</string>
+ <!-- Label for guest icon in quick settings user switcher [CHAR LIMIT=35] -->
+ <string name="guest_exit_quick_settings_button">Exit guest</string>
+ <!-- Message of the notification when guest mode is entered
+ and it's a ephemeral guest [CHAR LIMIT=60] -->
+ <string name="guest_notification_ephemeral">All activity will be deleted on exit</string>
+ <!-- Message of the notification when guest mode is entered
+ and it's not a ephemeral guest and it's a first time guest login [CHAR LIMIT=60] -->
+ <string name="guest_notification_non_ephemeral">You can save or delete your activity on exit</string>
+ <!-- Message of the notification when guest mode is entered
+ and it's not a ephemeral guest and it's not a first time guest login [CHAR LIMIT=NONE] -->
+ <string name="guest_notification_non_ephemeral_non_first_login">Reset to delete session
+ activity now, or you can save or delete activity on exit</string>
+
<!-- An option in a photo selection dialog to take a new photo [CHAR LIMIT=50] -->
<string name="user_image_take_photo">Take a photo</string>
<!-- An option in a photo selection dialog to choose a pre-existing image [CHAR LIMIT=50] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index feb4212035bc..b9c4030d9d0e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -239,6 +239,8 @@ public class Utils {
statusString = res.getString(R.string.battery_info_status_charging);
break;
}
+ } else if (batteryStatus.isPluggedInDock()) {
+ statusString = res.getString(R.string.battery_info_status_charging_dock);
} else {
statusString = res.getString(R.string.battery_info_status_charging_wireless);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index e5fd0ba5d9bc..bbb1ec6a5623 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -16,6 +16,7 @@
package com.android.settingslib.datetime;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.icu.text.TimeZoneFormat;
@@ -35,6 +36,7 @@ import androidx.core.text.TextDirectionHeuristicsCompat;
import com.android.i18n.timezone.CountryTimeZones;
import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping;
import com.android.i18n.timezone.TimeZoneFinder;
+import com.android.internal.app.LocaleHelper;
import com.android.settingslib.R;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,7 +101,8 @@ public class ZoneGetter {
TimeZoneFormat tzFormatter = TimeZoneFormat.getInstance(locale);
CharSequence gmtText = getGmtOffsetText(tzFormatter, locale, tz, now);
TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
- String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+ String zoneNameString = capitalizeForStandaloneDisplay(
+ locale, getZoneLongName(locale, timeZoneNames, tz, now));
if (zoneNameString == null) {
return gmtText;
}
@@ -108,6 +111,24 @@ public class ZoneGetter {
return TextUtils.concat(gmtText, " ", zoneNameString);
}
+ /**
+ * Capitalizes {@code toCapitalize} for standalone display, i.e. in lists. This is intended for
+ * use with "display name" strings from sources like ICU/CLDR which typically capitalize strings
+ * for the inclusion in the middle of sentences. Some locales (such as Polish) do not capitalize
+ * terms like "Coordinated Universal Time" as in English but do capitalize the first letter for
+ * standalone locations like lists, and so must be explicitly capitalized.
+ *
+ * @return the capitalized string, or {@code null} if the argument is null
+ */
+ @Nullable
+ public static String capitalizeForStandaloneDisplay(
+ Locale locale, @Nullable String toCapitalize) {
+ if (TextUtils.isEmpty(toCapitalize)) {
+ return toCapitalize;
+ }
+ return LocaleHelper.toSentenceCase(toCapitalize, locale);
+ }
+
public static List<Map<String, Object>> getZonesList(Context context) {
final Locale locale = context.getResources().getConfiguration().locale;
final Date now = new Date();
@@ -116,7 +137,7 @@ public class ZoneGetter {
// Work out whether the display names we would show by default would be ambiguous.
final boolean useExemplarLocationForLocalNames =
- shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
+ shouldUseExemplarLocationForLocalNames(locale, data, timeZoneNames);
// Generate the list of zone entries to return.
List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>();
@@ -124,7 +145,7 @@ public class ZoneGetter {
TimeZone tz = data.timeZones[i];
CharSequence gmtOffsetText = data.gmtOffsetTexts[i];
- CharSequence displayName = getTimeZoneDisplayName(data, timeZoneNames,
+ CharSequence displayName = getTimeZoneDisplayName(locale, data, timeZoneNames,
useExemplarLocationForLocalNames, tz, data.olsonIdsToDisplay[i]);
if (TextUtils.isEmpty(displayName)) {
displayName = gmtOffsetText;
@@ -181,15 +202,15 @@ public class ZoneGetter {
return olsonIds;
}
- private static boolean shouldUseExemplarLocationForLocalNames(ZoneGetterData data,
- TimeZoneNames timeZoneNames) {
+ private static boolean shouldUseExemplarLocationForLocalNames(Locale locale,
+ ZoneGetterData data, TimeZoneNames timeZoneNames) {
final Set<CharSequence> localZoneNames = new HashSet<>();
final Date now = new Date();
for (int i = 0; i < data.zoneCount; i++) {
final String olsonId = data.olsonIdsToDisplay[i];
if (data.localZoneIds.contains(olsonId)) {
final TimeZone tz = data.timeZones[i];
- CharSequence displayName = getZoneLongName(timeZoneNames, tz, now);
+ CharSequence displayName = getZoneLongName(locale, timeZoneNames, tz, now);
if (displayName == null) {
displayName = data.gmtOffsetTexts[i];
}
@@ -203,7 +224,7 @@ public class ZoneGetter {
return false;
}
- private static CharSequence getTimeZoneDisplayName(ZoneGetterData data,
+ private static CharSequence getTimeZoneDisplayName(Locale locale, ZoneGetterData data,
TimeZoneNames timeZoneNames, boolean useExemplarLocationForLocalNames, TimeZone tz,
String olsonId) {
final Date now = new Date();
@@ -212,7 +233,7 @@ public class ZoneGetter {
String displayName;
if (preferLongName) {
- displayName = getZoneLongName(timeZoneNames, tz, now);
+ displayName = getZoneLongName(locale, timeZoneNames, tz, now);
} else {
// Canonicalize the zone ID for ICU. It will only return valid strings for zone IDs
// that match ICUs zone IDs (which are similar but not guaranteed the same as those
@@ -223,10 +244,11 @@ public class ZoneGetter {
if (canonicalZoneId == null) {
canonicalZoneId = tz.getID();
}
- displayName = timeZoneNames.getExemplarLocationName(canonicalZoneId);
+ displayName = capitalizeForStandaloneDisplay(
+ locale, timeZoneNames.getExemplarLocationName(canonicalZoneId));
if (displayName == null || displayName.isEmpty()) {
// getZoneExemplarLocation can return null. Fall back to the long name.
- displayName = getZoneLongName(timeZoneNames, tz, now);
+ displayName = getZoneLongName(locale, timeZoneNames, tz, now);
}
}
@@ -237,11 +259,13 @@ public class ZoneGetter {
* Returns the long name for the timezone for the given locale at the time specified.
* Can return {@code null}.
*/
- private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) {
+ private static String getZoneLongName(
+ Locale locale, TimeZoneNames names, TimeZone tz, Date now) {
final TimeZoneNames.NameType nameType =
tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT
: TimeZoneNames.NameType.LONG_STANDARD;
- return names.getDisplayName(getCanonicalZoneId(tz), nameType, now.getTime());
+ return capitalizeForStandaloneDisplay(locale,
+ names.getDisplayName(getCanonicalZoneId(tz), nameType, now.getTime()));
}
private static String getCanonicalZoneId(TimeZone timeZone) {
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 64563be78fbb..d463170fae8c 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -25,7 +25,7 @@ android_test {
name: "SettingsLibTests",
defaults: [
"SettingsLibDefaults",
- "framework-wifi-test-defaults"
+ "framework-wifi-test-defaults",
],
certificate: "platform",
@@ -47,6 +47,7 @@ android_test {
"androidx.test.espresso.core",
"mockito-target-minus-junit4",
"truth-prebuilt",
+ "SettingsLibDeviceStateRotationLock",
"SettingsLibSettingsSpinner",
"SettingsLibUsageProgressBarPreference",
],
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 09b2a2e73c5b..336cdd3f259f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -365,6 +365,17 @@ public class UtilsTest {
}
@Test
+ public void getBatteryStatus_chargingDock_returnDockChargingString() {
+ final Intent intent = new Intent();
+ intent.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
+ intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_DOCK);
+ final Resources resources = mContext.getResources();
+
+ assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo(
+ resources.getString(R.string.battery_info_status_charging_dock));
+ }
+
+ @Test
public void getBatteryStatus_chargingWireless_returnWirelessChargingString() {
final Intent intent = new Intent();
intent.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
index f28572f5f71d..69484ed527b5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
@@ -37,9 +37,9 @@ import android.widget.ImageView;
import androidx.fragment.app.FragmentActivity;
import com.android.settingslib.R;
+import com.android.settingslib.RestrictedLockUtils;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -55,7 +55,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
@RunWith(RobolectricTestRunner.class)
-@Ignore
public class EditUserInfoControllerTest {
private static final int MAX_USER_NAME_LENGTH = 100;
@@ -87,6 +86,11 @@ public class EditUserInfoControllerTest {
}
@Override
+ RestrictedLockUtils.EnforcedAdmin getChangePhotoAdminRestriction(Context context) {
+ return null;
+ }
+
+ @Override
boolean isChangePhotoRestrictedByBase(Context context) {
return mPhotoRestrictedByBase;
}
@@ -98,7 +102,7 @@ public class EditUserInfoControllerTest {
mActivity = spy(ActivityController.of(new FragmentActivity()).get());
mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
mController = new TestEditUserInfoController();
- mPhotoRestrictedByBase = true;
+ mPhotoRestrictedByBase = false;
}
@Test
@@ -262,7 +266,7 @@ public class EditUserInfoControllerTest {
@Test
public void createDialog_canNotChangePhoto_nullPhotoController() {
- mPhotoRestrictedByBase = false;
+ mPhotoRestrictedByBase = true;
mController.createDialog(mActivity, mActivityStarter, mCurrentIcon,
"test", "title", null, null);
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index f490c87aa4ec..4a104276c18f 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -32,6 +32,7 @@ android_app {
],
static_libs: [
"junit",
+ "SettingsLibDeviceStateRotationLock",
"SettingsLibDisplayDensityUtils",
],
platform_apis: true,
@@ -55,6 +56,7 @@ android_test {
static_libs: [
"androidx.test.rules",
"mockito-target-minus-junit4",
+ "SettingsLibDeviceStateRotationLock",
"SettingsLibDisplayDensityUtils",
"platform-test-annotations",
"truth-prebuilt",
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7732da40aac2..3623c7821dfe 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -275,9 +275,6 @@
<!-- Whether to enable mute when off body by default. -->
<bool name="def_wearable_muteWhenOffBodyEnabled">true</bool>
- <!-- If a square screen, how rounded the corners are. Same as CSS border-radius property. -->
- <integer name="def_wearable_squareScreenCornerRoundness">0</integer>
-
<!-- Side button present -->
<bool name="def_wearable_sideButtonPresent">true</bool>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
index e425790110aa..3cb143966a7c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
@@ -32,5 +32,6 @@ public class DeviceSpecificSettings {
*/
public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = {
Settings.Secure.DISPLAY_DENSITY_FORCED,
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index dc166b4c2349..b9e565e9a78e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -82,6 +82,18 @@ public class GlobalSettings {
Settings.Global.USER_PREFERRED_REFRESH_RATE,
Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT,
Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH,
- Settings.Global.POWER_BUTTON_LONG_PRESS
+ Settings.Global.POWER_BUTTON_LONG_PRESS,
+ Settings.Global.Wearable.SMART_REPLIES_ENABLED,
+ Settings.Global.Wearable.CLOCKWORK_AUTO_TIME,
+ Settings.Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
+ Settings.Global.Wearable.CLOCKWORK_24HR_TIME,
+ Settings.Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
+ Settings.Global.Wearable.AMBIENT_ENABLED,
+ Settings.Global.Wearable.AMBIENT_TILT_TO_WAKE,
+ Settings.Global.Wearable.AMBIENT_TOUCH_TO_WAKE,
+ Settings.Global.Wearable.TOUCH_AND_HOLD_WATCH_FACE,
+ Settings.Global.Wearable.BATTERY_SAVER_MODE,
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 5eaf553a2047..56379f112d22 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -204,6 +204,8 @@ public class SecureSettings {
Settings.Secure.LOCKSCREEN_SHOW_WALLET,
Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER,
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
- Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON
+ Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
+ Settings.Secure.WEAR_TALKBACK_ENABLED,
+ Settings.Secure.HBM_SETTING_KEY
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index a6bfc408be7e..10ac5d9aed16 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -89,5 +89,9 @@ public class SystemSettings {
Settings.System.DISPLAY_COLOR_MODE,
Settings.System.ALARM_ALERT,
Settings.System.NOTIFICATION_LIGHT_PULSE,
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
+ Settings.System.CLOCKWORK_BLUETOOTH_SETTINGS_PREF,
+ Settings.System.UNREAD_NOTIFICATION_DOT_INDICATOR,
+ Settings.System.AUTO_LAUNCH_MEDIA_CONTROLS
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index acb33c356a8b..abd46dfc28be 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -163,13 +163,6 @@ public class GlobalSettingsValidators {
VALIDATORS.put(Global.Wearable.SMART_REPLIES_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(
- Global.Wearable.RETAIL_MODE,
- new DiscreteValueValidator(
- new String[] {
- String.valueOf(Global.Wearable.RETAIL_MODE_CONSUMER),
- String.valueOf(Global.Wearable.RETAIL_MODE_RETAIL)
- }));
- VALIDATORS.put(
Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
new DiscreteValueValidator(
new String[] {
@@ -250,7 +243,6 @@ public class GlobalSettingsValidators {
String.valueOf(Global.Wearable.STEM_TYPE_CONTACT_LAUNCH)
}));
VALIDATORS.put(Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Global.Wearable.CORNER_ROUNDNESS, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.SIDE_BUTTON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.BUTTON_SET, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.ANDROID_WEAR_VERSION, ANY_INTEGER_VALIDATOR);
@@ -308,6 +300,9 @@ public class GlobalSettingsValidators {
VALIDATORS.put(
Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(
+ Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
+ BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.WRIST_ORIENTATION_MODE,
@@ -317,6 +312,13 @@ public class GlobalSettingsValidators {
VALIDATORS.put(Global.USER_PREFERRED_RESOLUTION_WIDTH, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.WET_MODE_ON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.TOUCH_AND_HOLD_WATCH_FACE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.BEDTIME_MODE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(
+ Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MAX_RESET_COUNT,
+ NON_NEGATIVE_INTEGER_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9ee7b654046f..befc142b00ff 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -337,5 +337,7 @@ public class SecureSettingsValidators {
return true;
});
VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.WEAR_TALKBACK_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.HBM_SETTING_KEY, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 06712cc68b89..3e5802e0b98d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -207,5 +207,9 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.CLOCKWORK_BLUETOOTH_SETTINGS_PREF, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.UNREAD_NOTIFICATION_DOT_INDICATOR, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.AUTO_LAUNCH_MEDIA_CONTROLS, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b851232ace82..85d0b1820474 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -21,7 +21,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -35,7 +34,6 @@ import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Environment;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
@@ -227,15 +225,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");
// Populate bookmarks table with initial bookmarks
- boolean onlyCore = false;
- try {
- onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
- "package")).isOnlyCoreApps();
- } catch (RemoteException e) {
- }
- if (!onlyCore) {
- loadBookmarks(db);
- }
+ loadBookmarks(db);
// Load initial volume levels into DB
loadVolumeLevels(db);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 440bb67dc788..808ea9ede9dc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -41,6 +41,7 @@ import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import java.util.ArrayList;
import java.util.HashMap;
@@ -200,6 +201,9 @@ public class SettingsHelper {
} else if (Settings.Global.POWER_BUTTON_LONG_PRESS.equals(name)) {
setLongPressPowerBehavior(cr, value);
return;
+ } else if (Settings.System.ACCELEROMETER_ROTATION.equals(name)
+ && shouldSkipAutoRotateRestore()) {
+ return;
}
// Default case: write the restored value to settings
@@ -236,6 +240,12 @@ public class SettingsHelper {
}
}
+ private boolean shouldSkipAutoRotateRestore() {
+ // When device state based auto rotation settings are available, let's skip the restoring
+ // of the standard auto rotation settings to avoid conflicting setting values.
+ return DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(mContext);
+ }
+
public String onBackupValue(String name, String value) {
// Special processing for backing up ringtones & notification sounds
if (Settings.System.RINGTONE.equals(name)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ccfeae43e8b6..8683eac73c6c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -771,6 +771,12 @@ class SettingsProtoDumpUtil {
Settings.Global.ANGLE_EGL_FEATURES,
GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST);
+ dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST_MODE);
+ dumpSetting(s, p,
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX,
GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a6edb0f0e2e3..0090723513a2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5227,7 +5227,7 @@ public class SettingsProvider extends ContentProvider {
.getResources()
.getBoolean(R.bool.def_wearable_hotwordDetectionEnabled));
initGlobalSettingsDefaultValForWearLocked(
- Global.Wearable.SMART_REPLIES_ENABLED, false);
+ Global.Wearable.SMART_REPLIES_ENABLED, true);
Setting locationMode =
getSecureSettingsLocked(userId).getSettingLocked(Secure.LOCATION_MODE);
initGlobalSettingsDefaultValForWearLocked(
@@ -5236,8 +5236,6 @@ public class SettingsProvider extends ContentProvider {
&& !Integer.toString(Secure.LOCATION_MODE_OFF)
.equals(locationMode.getValue()));
initGlobalSettingsDefaultValForWearLocked(
- Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
- initGlobalSettingsDefaultValForWearLocked(
Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN);
initGlobalSettingsDefaultValForWearLocked(
@@ -5280,12 +5278,6 @@ public class SettingsProvider extends ContentProvider {
.getBoolean(R.bool.def_wearable_muteWhenOffBodyEnabled));
initGlobalSettingsDefaultValForWearLocked(
Global.Wearable.WEAR_OS_VERSION_STRING, "");
- initGlobalSettingsDefaultValForWearLocked(
- Global.Wearable.CORNER_ROUNDNESS,
- getContext()
- .getResources()
- .getInteger(
- R.integer.def_wearable_squareScreenCornerRoundness));
initGlobalSettingsDefaultValForWearLocked(Global.Wearable.BUTTON_SET, false);
initGlobalSettingsDefaultValForWearLocked(
Global.Wearable.SIDE_BUTTON,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index cce515444c1f..3b9ffc7569ea 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -102,8 +102,7 @@ public class SettingsBackupTest {
Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
Settings.System.SCREEN_BRIGHTNESS_FLOAT,
Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT,
- Settings.System.MULTI_AUDIO_FOCUS_ENABLED, // form-factor/OEM specific
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED
+ Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
);
private static final Set<String> BACKUP_DENY_LIST_GLOBAL_SETTINGS =
@@ -156,7 +155,6 @@ public class SettingsBackupTest {
Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
Settings.Global.BLE_SCAN_BACKGROUND_MODE,
- Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE,
Settings.Global.BLOCKED_SLICES,
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
@@ -422,6 +420,7 @@ public class SettingsBackupTest {
Settings.Global.RADIO_NFC,
Settings.Global.RADIO_WIFI,
Settings.Global.RADIO_WIMAX,
+ Settings.Global.REMOVE_GUEST_ON_EXIT,
Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
Settings.Global.RESTRICTED_NETWORKING_MODE,
@@ -512,6 +511,8 @@ public class SettingsBackupTest {
Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.ANGLE_EGL_FEATURES,
+ Settings.Global.ANGLE_DEFERLIST,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS,
@@ -599,21 +600,15 @@ public class SettingsBackupTest {
Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
Settings.Global.ENABLE_BACK_ANIMATION, // Temporary for T, dev option only
- Settings.Global.Wearable.BATTERY_SAVER_MODE,
Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
Settings.Global.Wearable.HAS_PAY_TOKENS,
Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
Settings.Global.Wearable.HOTWORD_DETECTION_ENABLED,
- Settings.Global.Wearable.SMART_REPLIES_ENABLED,
Settings.Global.Wearable.DEFAULT_VIBRATION,
Settings.Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
- Settings.Global.Wearable.RETAIL_MODE,
Settings.Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
Settings.Global.Wearable.BUG_REPORT,
Settings.Global.Wearable.SMART_ILLUMINATE_ENABLED,
- Settings.Global.Wearable.CLOCKWORK_AUTO_TIME,
- Settings.Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
- Settings.Global.Wearable.CLOCKWORK_24HR_TIME,
Settings.Global.Wearable.AUTO_WIFI,
Settings.Global.Wearable.WIFI_POWER_SAVE,
Settings.Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS,
@@ -628,9 +623,7 @@ public class SettingsBackupTest {
Settings.Global.Wearable.STEM_3_TYPE,
Settings.Global.Wearable.STEM_3_DATA,
Settings.Global.Wearable.STEM_3_DEFAULT_DATA,
- Settings.Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
Settings.Global.Wearable.WEAR_OS_VERSION_STRING,
- Settings.Global.Wearable.CORNER_ROUNDNESS,
Settings.Global.Wearable.BUTTON_SET,
Settings.Global.Wearable.SIDE_BUTTON,
Settings.Global.Wearable.ANDROID_WEAR_VERSION,
@@ -638,10 +631,7 @@ public class SettingsBackupTest {
Settings.Global.Wearable.SYSTEM_EDITION,
Settings.Global.Wearable.WEAR_PLATFORM_MR_NUMBER,
Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR,
- Settings.Global.Wearable.AMBIENT_ENABLED,
- Settings.Global.Wearable.AMBIENT_TILT_TO_WAKE,
Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED_DEV,
- Settings.Global.Wearable.AMBIENT_TOUCH_TO_WAKE,
Settings.Global.Wearable.AMBIENT_TILT_TO_BRIGHT,
Settings.Global.Wearable.DECOMPOSABLE_WATCHFACE,
Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED,
@@ -657,15 +647,17 @@ public class SettingsBackupTest {
Settings.Global.Wearable.OEM_SETUP_VERSION,
Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
Settings.Global.Wearable.UNGAZE_ENABLED,
- Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
Settings.Global.Wearable.WRIST_ORIENTATION_MODE,
Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
- Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
Settings.Global.Wearable.WET_MODE_ON,
- Settings.Global.Wearable.COOLDOWN_MODE_ON);
+ Settings.Global.Wearable.COOLDOWN_MODE_ON,
+ Settings.Global.Wearable.CHARGING_SOUNDS_ENABLED,
+ Settings.Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED,
+ Settings.Global.Wearable.BEDTIME_MODE,
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MAX_RESET_COUNT);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index 4f7b494c0e71..ee76dbf8ce70 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -73,6 +73,8 @@ public class SettingsHelperTest {
when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))).thenReturn(
mTelephonyManager);
when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getContentResolver()).thenReturn(getContentResolver());
mSettingsHelper = spy(new SettingsHelper(mContext));
}
@@ -305,6 +307,63 @@ public class SettingsHelperTest {
new String[] { "he-IL", "id-ID", "yi" })); // supported
}
+ @Test
+ public void restoreValue_autoRotation_deviceStateAutoRotationDisabled_restoresValue() {
+ when(mResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+ .thenReturn(new String[]{});
+ int previousValue = 0;
+ int newValue = 1;
+ setAutoRotationSettingValue(previousValue);
+
+ restoreAutoRotationSetting(newValue);
+
+ assertThat(getAutoRotationSettingValue()).isEqualTo(newValue);
+ }
+
+ @Test
+ public void restoreValue_autoRotation_deviceStateAutoRotationEnabled_doesNotRestoreValue() {
+ when(mResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+ .thenReturn(new String[]{"0:1", "1:1"});
+ int previousValue = 0;
+ int newValue = 1;
+ setAutoRotationSettingValue(previousValue);
+
+ restoreAutoRotationSetting(newValue);
+
+ assertThat(getAutoRotationSettingValue()).isEqualTo(previousValue);
+ }
+
+ private int getAutoRotationSettingValue() {
+ return Settings.System.getInt(
+ getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION,
+ /* default= */ -1);
+ }
+
+ private void setAutoRotationSettingValue(int value) {
+ Settings.System.putInt(
+ getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION,
+ value
+ );
+ }
+
+ private void restoreAutoRotationSetting(int newValue) {
+ mSettingsHelper.restoreValue(
+ mContext,
+ getContentResolver(),
+ new ContentValues(),
+ /* destination= */ Settings.System.CONTENT_URI,
+ /* name= */ Settings.System.ACCELEROMETER_ROTATION,
+ /* value= */ String.valueOf(newValue),
+ /* restoredFromSdkInt= */ 0);
+ }
+
+ private ContentResolver getContentResolver() {
+ return InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getContentResolver();
+ }
+
private void clearLongPressPowerValues() {
ContentResolver cr = InstrumentationRegistry.getInstrumentation().getTargetContext()
.getContentResolver();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 3b862ffbbd9e..c6e126004ff1 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -505,6 +505,12 @@
<!-- Permissions needed for CTS test - CtsLocaleManagerTestCases -->
<uses-permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES" />
+ <!-- Permissions used for manual testing of time detection behavior. -->
+ <uses-permission android:name="android.permission.SUGGEST_MANUAL_TIME" />
+ <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME" />
+ <uses-permission android:name="android.permission.SUGGEST_NETWORK_TIME" />
+ <uses-permission android:name="android.permission.SUGGEST_GNSS_TIME" />
+
<!-- Permission required for CTS test - android.server.biometrics -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
@@ -646,6 +652,7 @@
<!-- Permission required to run the `vm` tool which manages on-device virtual machines -->
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.DEBUG_VIRTUAL_MACHINE" />
<!-- Permission required to run GtsAssistantTestCases -->
@@ -683,12 +690,15 @@
<!-- Permission required for CTS test - CtsAppEnumerationTestCases -->
<uses-permission android:name="android.permission.MAKE_UID_VISIBLE" />
- <!-- Permission required for CTS test - CtsKeystoreTestCases -->
- <uses-permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" />
+ <!-- Permission required for CTS test - CtsInputTestCases -->
+ <uses-permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY" />
<!-- Permission required for CTS test - CtsDevicePolicyManagerTestCases -->
<uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" />
+ <!-- Permission required for CTS test - CtsKeystoreTestCases -->
+ <uses-permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 1ce4c64fd8b8..68679c794c35 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -572,6 +572,7 @@ public class BugreportProgressService extends Service {
break;
case INTENT_BUGREPORT_DONE:
maybeShowWarningMessageAndCloseNotification(id);
+ break;
case INTENT_BUGREPORT_CANCEL:
cancel(id);
break;
@@ -843,16 +844,11 @@ public class BugreportProgressService extends Service {
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
}
- @GuardedBy("mLock")
- private void stopProgressLocked(int id) {
- stopProgressLocked(id, /* cancelNotification */ true);
- }
-
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
@GuardedBy("mLock")
- private void stopProgressLocked(int id, boolean cancelNotification) {
+ private void stopProgressLocked(int id) {
if (mBugreportInfos.indexOfKey(id) < 0) {
Log.w(TAG, "ID not watched: " + id);
} else {
@@ -862,12 +858,10 @@ public class BugreportProgressService extends Service {
// Must stop foreground service first, otherwise notif.cancel() will fail below.
stopForegroundWhenDoneLocked(id);
- if (cancelNotification) {
- Log.d(TAG, "stopProgress(" + id + "): cancel notification");
- NotificationManager.from(mContext).cancel(id);
- } else {
- Log.d(TAG, "stopProgress(" + id + ")");
- }
+
+ Log.d(TAG, "stopProgress(" + id + "): cancel notification");
+ NotificationManager.from(mContext).cancel(id);
+
stopSelfWhenDoneLocked();
}
@@ -1112,30 +1106,7 @@ public class BugreportProgressService extends Service {
return;
}
- if (mIsWatch) {
- // Wear wants to send the notification directly and not wait for the user to tap on the
- // notification.
- triggerShareBugreportAndLocalNotification(info);
- } else {
- triggerLocalNotification(info);
- }
- }
-
- /**
- * Responsible for starting the bugerport sharing process and posting a notification which
- * shows that the bugreport has been taken and that the sharing process has kicked-off.
- */
- private void triggerShareBugreportAndLocalNotification(final BugreportInfo info) {
- boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
- if (!isPlainText) {
- // Already zipped, share it right away.
- shareBugreport(info.id, info, /* showWarning */ false,
- /* cancelNotificationWhenStoppingProgress */ false);
- sendBugreportNotification(info, mTakingScreenshot);
- } else {
- // Asynchronously zip the file first, then share it.
- shareAndPostNotificationForZippedBugreport(info, mTakingScreenshot);
- }
+ triggerLocalNotification(info);
}
/**
@@ -1249,16 +1220,14 @@ public class BugreportProgressService extends Service {
}
private void shareBugreport(int id, BugreportInfo sharedInfo) {
- shareBugreport(id, sharedInfo, !hasUserDecidedNotToGetWarningMessage(),
- /* cancelNotificationWhenStoppingProgress */ true);
+ shareBugreport(id, sharedInfo, !hasUserDecidedNotToGetWarningMessage());
}
/**
* Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
* intent, but issuing a warning dialog the first time.
*/
- private void shareBugreport(int id, BugreportInfo sharedInfo, boolean showWarning,
- boolean cancelNotificationWhenStoppingProgress) {
+ private void shareBugreport(int id, BugreportInfo sharedInfo, boolean showWarning) {
MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE);
BugreportInfo info;
synchronized (mLock) {
@@ -1307,7 +1276,7 @@ public class BugreportProgressService extends Service {
}
synchronized (mLock) {
// ... and stop watching this process.
- stopProgressLocked(id, cancelNotificationWhenStoppingProgress);
+ stopProgressLocked(id);
}
}
@@ -1362,7 +1331,7 @@ public class BugreportProgressService extends Service {
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.setDeleteIntent(newCancelIntent(mContext, info));
} else {
- // Device is a watch.
+ // Device is a watch
if (hasUserDecidedNotToGetWarningMessage()) {
// No action button needed for the notification. User can swipe to dimiss.
builder.setActions(new Action[0]);
@@ -1433,24 +1402,6 @@ public class BugreportProgressService extends Service {
}
/**
- * Zips a bugreport, shares it, and sends for it a bugreport notification.
- */
- private void shareAndPostNotificationForZippedBugreport(final BugreportInfo info,
- final boolean takingScreenshot) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- Looper.prepare();
- zipBugreport(info);
- shareBugreport(info.id, info, /* showWarning */ false,
- /* cancelNotificationWhenStoppingProgress */ false);
- sendBugreportNotification(info, mTakingScreenshot);
- return null;
- }
- }.execute();
- }
-
- /**
* Zips a bugreport file, returning the path to the new file (or to the
* original in case of failure).
*/
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index f05c1e2e76f2..de9e1f4ccec5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -125,6 +125,7 @@ android_library {
],
manifest: "AndroidManifest.xml",
+ javacflags: ["-Adagger.fastInit=enabled"],
kotlincflags: ["-Xjvm-default=enable"],
plugins: ["dagger2-compiler"],
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 4b07eaf780e4..791e21602c51 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -10,7 +10,6 @@ alexflo@google.com
asc@google.com
awickham@google.com
beverlyt@google.com
-brockman@google.com
brzezinski@google.com
brycelee@google.com
ccassidy@google.com
@@ -33,6 +32,7 @@ jonmiranda@google.com
joshtrask@google.com
juliacr@google.com
juliatuttle@google.com
+justinkoh@google.com
kchyn@google.com
kozynski@google.com
kprevas@google.com
@@ -68,6 +68,7 @@ twickham@google.com
vadimt@google.com
victortulias@google.com
winsonc@google.com
+wleshner@google.com
yurilin@google.com
xuqiu@google.com
zakcohen@google.com
diff --git a/packages/SystemUI/compose/core/Android.bp b/packages/SystemUI/compose/core/Android.bp
new file mode 100644
index 000000000000..4cfe39225a9b
--- /dev/null
+++ b/packages/SystemUI/compose/core/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUIComposeCore",
+ manifest: "AndroidManifest.xml",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ ],
+
+ kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/libs/WindowManager/Shell/res/color/unfold_transition_background.xml b/packages/SystemUI/compose/core/AndroidManifest.xml
index 63289a3f75d9..83c442d2d6f2 100644
--- a/libs/WindowManager/Shell/res/color/unfold_transition_background.xml
+++ b/packages/SystemUI/compose/core/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
+<!--
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Matches taskbar color -->
- <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
-</selector>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.core">
+
+
+</manifest>
diff --git a/packages/SystemUI/compose/core/TEST_MAPPING b/packages/SystemUI/compose/core/TEST_MAPPING
new file mode 100644
index 000000000000..dc243d2fd8f5
--- /dev/null
+++ b/packages/SystemUI/compose/core/TEST_MAPPING
@@ -0,0 +1,37 @@
+{
+ "presubmit": [
+ {
+ "name": "SystemUIComposeCoreTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "SystemUIComposeFeaturesTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "SystemUIComposeGalleryTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt
new file mode 100644
index 000000000000..6bbac69752a3
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2022 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.compose
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Build
+import android.view.View
+import android.view.Window
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.window.DialogWindowProvider
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+
+/***************************************************************************************************
+ * This file was forked from
+ * https://github.com/google/accompanist/blob/main/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt
+ * and will be removed once it lands in AndroidX.
+ **************************************************************************************************/
+
+/**
+ * A class which provides easy-to-use utilities for updating the System UI bar
+ * colors within Jetpack Compose.
+ *
+ * @sample com.google.accompanist.sample.systemuicontroller.SystemUiControllerSample
+ */
+@Stable
+interface SystemUiController {
+
+ /**
+ * Property which holds the status bar visibility. If set to true, show the status bar,
+ * otherwise hide the status bar.
+ */
+ var isStatusBarVisible: Boolean
+
+ /**
+ * Property which holds the navigation bar visibility. If set to true, show the navigation bar,
+ * otherwise hide the navigation bar.
+ */
+ var isNavigationBarVisible: Boolean
+
+ /**
+ * Property which holds the status & navigation bar visibility. If set to true, show both bars,
+ * otherwise hide both bars.
+ */
+ var isSystemBarsVisible: Boolean
+ get() = isNavigationBarVisible && isStatusBarVisible
+ set(value) {
+ isStatusBarVisible = value
+ isNavigationBarVisible = value
+ }
+
+ /**
+ * Set the status bar color.
+ *
+ * @param color The **desired** [Color] to set. This may require modification if running on an
+ * API level that only supports white status bar icons.
+ * @param darkIcons Whether dark status bar icons would be preferable.
+ * @param transformColorForLightContent A lambda which will be invoked to transform [color] if
+ * dark icons were requested but are not available. Defaults to applying a black scrim.
+ *
+ * @see statusBarDarkContentEnabled
+ */
+ fun setStatusBarColor(
+ color: Color,
+ darkIcons: Boolean = color.luminance() > 0.5f,
+ transformColorForLightContent: (Color) -> Color = BlackScrimmed
+ )
+
+ /**
+ * Set the navigation bar color.
+ *
+ * @param color The **desired** [Color] to set. This may require modification if running on an
+ * API level that only supports white navigation bar icons. Additionally this will be ignored
+ * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or the
+ * system UI automatically applies background protection in other navigation modes.
+ * @param darkIcons Whether dark navigation bar icons would be preferable.
+ * @param navigationBarContrastEnforced Whether the system should ensure that the navigation
+ * bar has enough contrast when a fully transparent background is requested. Only supported on
+ * API 29+.
+ * @param transformColorForLightContent A lambda which will be invoked to transform [color] if
+ * dark icons were requested but are not available. Defaults to applying a black scrim.
+ *
+ * @see navigationBarDarkContentEnabled
+ * @see navigationBarContrastEnforced
+ */
+ fun setNavigationBarColor(
+ color: Color,
+ darkIcons: Boolean = color.luminance() > 0.5f,
+ navigationBarContrastEnforced: Boolean = true,
+ transformColorForLightContent: (Color) -> Color = BlackScrimmed
+ )
+
+ /**
+ * Set the status and navigation bars to [color].
+ *
+ * @see setStatusBarColor
+ * @see setNavigationBarColor
+ */
+ fun setSystemBarsColor(
+ color: Color,
+ darkIcons: Boolean = color.luminance() > 0.5f,
+ isNavigationBarContrastEnforced: Boolean = true,
+ transformColorForLightContent: (Color) -> Color = BlackScrimmed
+ ) {
+ setStatusBarColor(color, darkIcons, transformColorForLightContent)
+ setNavigationBarColor(
+ color,
+ darkIcons,
+ isNavigationBarContrastEnforced,
+ transformColorForLightContent
+ )
+ }
+
+ /**
+ * Property which holds whether the status bar icons + content are 'dark' or not.
+ */
+ var statusBarDarkContentEnabled: Boolean
+
+ /**
+ * Property which holds whether the navigation bar icons + content are 'dark' or not.
+ */
+ var navigationBarDarkContentEnabled: Boolean
+
+ /**
+ * Property which holds whether the status & navigation bar icons + content are 'dark' or not.
+ */
+ var systemBarsDarkContentEnabled: Boolean
+ get() = statusBarDarkContentEnabled && navigationBarDarkContentEnabled
+ set(value) {
+ statusBarDarkContentEnabled = value
+ navigationBarDarkContentEnabled = value
+ }
+
+ /**
+ * Property which holds whether the system is ensuring that the navigation bar has enough
+ * contrast when a fully transparent background is requested. Only has an affect when running
+ * on Android API 29+ devices.
+ */
+ var isNavigationBarContrastEnforced: Boolean
+}
+
+/**
+ * Remembers a [SystemUiController] for the given [window].
+ *
+ * If no [window] is provided, an attempt to find the correct [Window] is made.
+ *
+ * First, if the [LocalView]'s parent is a [DialogWindowProvider], then that dialog's [Window] will
+ * be used.
+ *
+ * Second, we attempt to find [Window] for the [Activity] containing the [LocalView].
+ *
+ * If none of these are found (such as may happen in a preview), then the functionality of the
+ * returned [SystemUiController] will be degraded, but won't throw an exception.
+ */
+@Composable
+fun rememberSystemUiController(
+ window: Window? = findWindow(),
+): SystemUiController {
+ val view = LocalView.current
+ return remember(view, window) { AndroidSystemUiController(view, window) }
+}
+
+@Composable
+private fun findWindow(): Window? =
+ (LocalView.current.parent as? DialogWindowProvider)?.window
+ ?: LocalView.current.context.findWindow()
+
+private tailrec fun Context.findWindow(): Window? =
+ when (this) {
+ is Activity -> window
+ is ContextWrapper -> baseContext.findWindow()
+ else -> null
+ }
+
+/**
+ * A helper class for setting the navigation and status bar colors for a [View], gracefully
+ * degrading behavior based upon API level.
+ *
+ * Typically you would use [rememberSystemUiController] to remember an instance of this.
+ */
+internal class AndroidSystemUiController(
+ private val view: View,
+ private val window: Window?
+) : SystemUiController {
+ private val windowInsetsController = window?.let {
+ WindowCompat.getInsetsController(it, view)
+ }
+
+ override fun setStatusBarColor(
+ color: Color,
+ darkIcons: Boolean,
+ transformColorForLightContent: (Color) -> Color
+ ) {
+ statusBarDarkContentEnabled = darkIcons
+
+ window?.statusBarColor = when {
+ darkIcons && windowInsetsController?.isAppearanceLightStatusBars != true -> {
+ // If we're set to use dark icons, but our windowInsetsController call didn't
+ // succeed (usually due to API level), we instead transform the color to maintain
+ // contrast
+ transformColorForLightContent(color)
+ }
+ else -> color
+ }.toArgb()
+ }
+
+ override fun setNavigationBarColor(
+ color: Color,
+ darkIcons: Boolean,
+ navigationBarContrastEnforced: Boolean,
+ transformColorForLightContent: (Color) -> Color
+ ) {
+ navigationBarDarkContentEnabled = darkIcons
+ isNavigationBarContrastEnforced = navigationBarContrastEnforced
+
+ window?.navigationBarColor = when {
+ darkIcons && windowInsetsController?.isAppearanceLightNavigationBars != true -> {
+ // If we're set to use dark icons, but our windowInsetsController call didn't
+ // succeed (usually due to API level), we instead transform the color to maintain
+ // contrast
+ transformColorForLightContent(color)
+ }
+ else -> color
+ }.toArgb()
+ }
+
+ override var isStatusBarVisible: Boolean
+ get() {
+ return ViewCompat.getRootWindowInsets(view)
+ ?.isVisible(WindowInsetsCompat.Type.statusBars()) == true
+ }
+ set(value) {
+ if (value) {
+ windowInsetsController?.show(WindowInsetsCompat.Type.statusBars())
+ } else {
+ windowInsetsController?.hide(WindowInsetsCompat.Type.statusBars())
+ }
+ }
+
+ override var isNavigationBarVisible: Boolean
+ get() {
+ return ViewCompat.getRootWindowInsets(view)
+ ?.isVisible(WindowInsetsCompat.Type.navigationBars()) == true
+ }
+ set(value) {
+ if (value) {
+ windowInsetsController?.show(WindowInsetsCompat.Type.navigationBars())
+ } else {
+ windowInsetsController?.hide(WindowInsetsCompat.Type.navigationBars())
+ }
+ }
+
+ override var statusBarDarkContentEnabled: Boolean
+ get() = windowInsetsController?.isAppearanceLightStatusBars == true
+ set(value) {
+ windowInsetsController?.isAppearanceLightStatusBars = value
+ }
+
+ override var navigationBarDarkContentEnabled: Boolean
+ get() = windowInsetsController?.isAppearanceLightNavigationBars == true
+ set(value) {
+ windowInsetsController?.isAppearanceLightNavigationBars = value
+ }
+
+ override var isNavigationBarContrastEnforced: Boolean
+ get() = Build.VERSION.SDK_INT >= 29 && window?.isNavigationBarContrastEnforced == true
+ set(value) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ window?.isNavigationBarContrastEnforced = value
+ }
+ }
+}
+
+private val BlackScrim = Color(0f, 0f, 0f, 0.3f) // 30% opaque black
+private val BlackScrimmed: (Color) -> Color = { original ->
+ BlackScrim.compositeOver(original)
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
new file mode 100644
index 000000000000..e4d1bcf0bf89
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.compose.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+/**
+ * The Material 3 theme that should wrap all SystemUI Composables.
+ */
+@Composable
+fun SystemUITheme(
+ isDarkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable () -> Unit,
+) {
+ val context = LocalContext.current
+
+ // TODO(b/230605885): Define our typography and color scheme.
+ val colorScheme = if (isDarkTheme) {
+ dynamicDarkColorScheme(context)
+ } else {
+ dynamicLightColorScheme(context)
+ }
+ val typography = Typography()
+
+ MaterialTheme(colorScheme, typography) {
+ content()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp
new file mode 100644
index 000000000000..f8023e2519f8
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+// TODO(b/230606318): Make those host tests instead of device tests.
+android_test {
+ name: "SystemUIComposeCoreTests",
+ manifest: "AndroidManifest.xml",
+ test_suites: ["device-tests"],
+ sdk_version: "current",
+ certificate: "platform",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "SystemUIComposeCore",
+
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui-test-junit4",
+ "androidx.compose.ui_ui-test-manifest",
+ ],
+
+ kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/core/tests/AndroidManifest.xml b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..729ab989cdc0
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.core.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.systemui.compose.core.tests"
+ android:label="Tests for SystemUIComposeCore"/>
+
+</manifest> \ No newline at end of file
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt
new file mode 100644
index 000000000000..f1b9e9f58680
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.compose.theme
+
+import androidx.compose.material3.Text
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SystemUIThemeTest {
+ @get:Rule
+ val composeRule = createComposeRule()
+
+ @Test
+ fun testThemeShowsContent() {
+ composeRule.setContent {
+ SystemUITheme {
+ Text("foo")
+ }
+ }
+
+ composeRule.onNodeWithText("foo").assertIsDisplayed()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
new file mode 100644
index 000000000000..40218de94258
--- /dev/null
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUIComposeFeatures",
+ manifest: "AndroidManifest.xml",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "SystemUIComposeCore",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ ],
+
+ kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/compose/features/AndroidManifest.xml b/packages/SystemUI/compose/features/AndroidManifest.xml
new file mode 100644
index 000000000000..0aea99d4e960
--- /dev/null
+++ b/packages/SystemUI/compose/features/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.features">
+
+
+</manifest>
diff --git a/packages/SystemUI/compose/features/TEST_MAPPING b/packages/SystemUI/compose/features/TEST_MAPPING
new file mode 100644
index 000000000000..7430acb2e900
--- /dev/null
+++ b/packages/SystemUI/compose/features/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+ "presubmit": [
+ {
+ "name": "SystemUIComposeFeaturesTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "SystemUIComposeGalleryTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
new file mode 100644
index 000000000000..73d5e3521d0c
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+/**
+ * This is an example Compose feature, which shows a text and a count that is incremented when
+ * clicked.
+ */
+@Composable
+fun ExampleFeature(text: String, modifier: Modifier = Modifier) {
+ Surface(
+ modifier,
+ color = MaterialTheme.colorScheme.primaryContainer,
+ shape = RoundedCornerShape(28.dp),
+ ) {
+ var count by remember { mutableStateOf(0) }
+ Column(
+ Modifier
+ .clickable { count++ }
+ .padding(16.dp),
+ ) {
+ Text(text)
+ Text("I was clicked $count times.")
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/tests/Android.bp b/packages/SystemUI/compose/features/tests/Android.bp
new file mode 100644
index 000000000000..ff534bd01fd3
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+// TODO(b/230606318): Make those host tests instead of device tests.
+android_test {
+ name: "SystemUIComposeFeaturesTests",
+ manifest: "AndroidManifest.xml",
+ test_suites: ["device-tests"],
+ sdk_version: "current",
+ certificate: "platform",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "SystemUIComposeFeatures",
+
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui-test-junit4",
+ "androidx.compose.ui_ui-test-manifest",
+ ],
+
+ kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/features/tests/AndroidManifest.xml b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..5e54c1f353d2
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.features.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.systemui.compose.features.tests"
+ android:label="Tests for SystemUIComposeFeatures"/>
+
+</manifest> \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt b/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt
new file mode 100644
index 000000000000..b120b963ae5e
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ExampleFeatureTest {
+ @get:Rule
+ val composeRule = createComposeRule()
+
+ @Test
+ fun testProvidedTextIsDisplayed() {
+ composeRule.setContent {
+ ExampleFeature("foo")
+ }
+
+ composeRule.onNodeWithText("foo").assertIsDisplayed()
+ }
+
+ @Test
+ fun testCountIsIncreasedWhenClicking() {
+ composeRule.setContent {
+ ExampleFeature("foo")
+ }
+
+ composeRule.onNodeWithText("I was clicked 0 times.")
+ .assertIsDisplayed()
+ .performClick()
+ composeRule.onNodeWithText("I was clicked 1 times.").assertIsDisplayed()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/Android.bp b/packages/SystemUI/compose/gallery/Android.bp
new file mode 100644
index 000000000000..030ad854992a
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUIComposeGalleryLib",
+ manifest: "AndroidManifest.xml",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ resource_dirs: [
+ "res",
+ ],
+
+ static_libs: [
+ "SystemUIComposeCore",
+ "SystemUIComposeFeatures",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ "androidx.compose.material_material-icons-extended",
+ "androidx.activity_activity-compose",
+ "androidx.navigation_navigation-compose",
+
+ "androidx.appcompat_appcompat",
+ ],
+
+ kotlincflags: ["-Xjvm-default=all"],
+}
+
+android_app {
+ name: "SystemUIComposeGallery",
+ defaults: ["platform_app_defaults"],
+
+ static_libs: [
+ "SystemUIComposeGalleryLib",
+ ],
+
+ platform_apis: true,
+ system_ext_specific: true,
+ certificate: "platform",
+ privileged: true,
+
+ optimize: {
+ proguard_flags_files: ["proguard-rules.pro"],
+ },
+
+ dxflags: ["--multi-dex"],
+}
diff --git a/packages/SystemUI/compose/gallery/AndroidManifest.xml b/packages/SystemUI/compose/gallery/AndroidManifest.xml
new file mode 100644
index 000000000000..81132632079a
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.gallery">
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.SystemUIGallery">
+ <activity
+ android:name=".GalleryActivity"
+ android:exported="true"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/SystemUI/compose/gallery/TEST_MAPPING b/packages/SystemUI/compose/gallery/TEST_MAPPING
new file mode 100644
index 000000000000..c7f8a9216418
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "SystemUIComposeGalleryTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/proguard-rules.pro b/packages/SystemUI/compose/gallery/proguard-rules.pro
new file mode 100644
index 000000000000..481bb4348141
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml b/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000000..966abaff2074
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeColor="#00000000"
+ android:strokeWidth="1" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml b/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000000..61bb79edb709
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+</vector>
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000000..03eed2533da2
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000000..03eed2533da2
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 000000000000..c209e78ecd37
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 000000000000..b2dfe3d1ba5c
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 000000000000..4f0f1d64e58b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 000000000000..62b611da0816
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 000000000000..948a3070fe34
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 000000000000..1b9a6956b3ac
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 000000000000..28d4b77f9f03
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 000000000000..9287f5083623
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 000000000000..aa7d6427e6fa
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 000000000000..9126ae37cbc3
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/values-night/themes.xml b/packages/SystemUI/compose/gallery/res/values-night/themes.xml
new file mode 100644
index 000000000000..58d20b88c13b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values-night/themes.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <style name="Theme.SystemUIGallery" parent="Theme.AppCompat.DayNight.NoActionBar">
+ <item name="android:statusBarColor" tools:targetApi="l">
+ @android:color/transparent
+ </item>
+ <item name="android:navigationBarColor" tools:targetApi="l">
+ @android:color/transparent
+ </item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/colors.xml b/packages/SystemUI/compose/gallery/res/values/colors.xml
new file mode 100644
index 000000000000..a2fcbffc26c0
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <color name="ic_launcher_background">#FFFFFF</color>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/strings.xml b/packages/SystemUI/compose/gallery/res/values/strings.xml
new file mode 100644
index 000000000000..86bdb0568837
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Application name [CHAR LIMIT=NONE] -->
+ <string name="app_name">SystemUI Gallery</string>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/themes.xml b/packages/SystemUI/compose/gallery/res/values/themes.xml
new file mode 100644
index 000000000000..6e5e99832f09
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/themes.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <style name="Theme.SystemUIGallery" parent="Theme.AppCompat.DayNight.NoActionBar">
+ <item name="android:statusBarColor" tools:targetApi="l">
+ @android:color/transparent
+ </item>
+ <item name="android:navigationBarColor" tools:targetApi="l">
+ @android:color/transparent
+ </item>
+ <item name="android:windowLightStatusBar">true</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
new file mode 100644
index 000000000000..ac9fdbf2eee9
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+
+/** The screen that shows all the Material 3 colors. */
+@Composable
+fun ColorsScreen() {
+ val colors = MaterialTheme.colorScheme
+ LazyColumn {
+ item { ColorTile(colors.primary, "primary") }
+ item { ColorTile(colors.onPrimary, "onPrimary") }
+ item { ColorTile(colors.primaryContainer, "primaryContainer") }
+ item { ColorTile(colors.onPrimaryContainer, "onPrimaryContainer") }
+ item { ColorTile(colors.inversePrimary, "inversePrimary") }
+ item { ColorTile(colors.secondary, "secondary") }
+ item { ColorTile(colors.onSecondary, "onSecondary") }
+ item { ColorTile(colors.secondaryContainer, "secondaryContainer") }
+ item { ColorTile(colors.onSecondaryContainer, "onSecondaryContainer") }
+ item { ColorTile(colors.tertiary, "tertiary") }
+ item { ColorTile(colors.onTertiary, "onTertiary") }
+ item { ColorTile(colors.tertiaryContainer, "tertiaryContainer") }
+ item { ColorTile(colors.onTertiaryContainer, "onTertiaryContainer") }
+ item { ColorTile(colors.background, "background") }
+ item { ColorTile(colors.onBackground, "onBackground") }
+ item { ColorTile(colors.surface, "surface") }
+ item { ColorTile(colors.onSurface, "onSurface") }
+ item { ColorTile(colors.surfaceVariant, "surfaceVariant") }
+ item { ColorTile(colors.onSurfaceVariant, "onSurfaceVariant") }
+ item { ColorTile(colors.inverseSurface, "inverseSurface") }
+ item { ColorTile(colors.inverseOnSurface, "inverseOnSurface") }
+ item { ColorTile(colors.error, "error") }
+ item { ColorTile(colors.onError, "onError") }
+ item { ColorTile(colors.errorContainer, "errorContainer") }
+ item { ColorTile(colors.onErrorContainer, "onErrorContainer") }
+ item { ColorTile(colors.outline, "outline") }
+ }
+}
+
+@Composable
+private fun ColorTile(
+ color: Color,
+ name: String,
+) {
+ Row(
+ Modifier.padding(16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ val shape = RoundedCornerShape(16.dp)
+ Spacer(
+ Modifier
+ .border(1.dp, MaterialTheme.colorScheme.onBackground, shape)
+ .background(color, shape)
+ .size(64.dp)
+ )
+ Spacer(Modifier.width(16.dp))
+ Text(name)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
new file mode 100644
index 000000000000..e8e6080b9fa1
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
@@ -0,0 +1,86 @@
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.BrightnessHigh
+import androidx.compose.material.icons.filled.BrightnessLow
+import androidx.compose.material.icons.filled.FormatSize
+import androidx.compose.material.icons.filled.FormatTextdirectionLToR
+import androidx.compose.material.icons.filled.FormatTextdirectionRToL
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+
+enum class FontScale(val scale: Float) {
+ Small(0.85f),
+ Normal(1f),
+ Big(1.15f),
+ Bigger(1.30f),
+}
+
+/** A configuration panel that allows to toggle the theme, font scale and layout direction. */
+@Composable
+fun ConfigurationControls(
+ isDarkTheme: Boolean,
+ fontScale: FontScale,
+ layoutDirection: LayoutDirection,
+ onChangeTheme: () -> Unit,
+ onChangeLayoutDirection: () -> Unit,
+ onChangeFontScale: () -> Unit,
+) {
+ LazyRow {
+ // Dark/light theme.
+ item {
+ TextButton(onChangeTheme) {
+ val text: String
+ val icon: ImageVector
+ if (isDarkTheme) {
+ icon = Icons.Default.BrightnessHigh
+ text = "Dark"
+ } else {
+ icon = Icons.Default.BrightnessLow
+ text = "Light"
+ }
+
+ Icon(icon, null)
+ Spacer(Modifier.width(8.dp))
+ Text(text)
+ }
+ }
+
+ // Font scale.
+ item {
+ TextButton(onChangeFontScale) {
+ Icon(Icons.Default.FormatSize, null)
+ Spacer(Modifier.width(8.dp))
+
+ Text(fontScale.name)
+ }
+ }
+
+ // Layout direction.
+ item {
+ TextButton(onChangeLayoutDirection) {
+ when (layoutDirection) {
+ LayoutDirection.Ltr -> {
+ Icon(Icons.Default.FormatTextdirectionLToR, null)
+ Spacer(Modifier.width(8.dp))
+ Text("LTR")
+ }
+ LayoutDirection.Rtl -> {
+ Icon(Icons.Default.FormatTextdirectionRToL, null)
+ Spacer(Modifier.width(8.dp))
+ Text("RTL")
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
new file mode 100644
index 000000000000..1c6b9b09ff3a
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import com.android.systemui.ExampleFeature
+
+/** The screen that shows ExampleFeature. */
+@Composable
+fun ExampleFeatureScreen() {
+ Column {
+ ExampleFeature("This is an example feature!")
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt
new file mode 100644
index 000000000000..ee38511aad01
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import android.os.Bundle
+import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.Color
+import androidx.core.view.WindowCompat
+import com.android.systemui.compose.rememberSystemUiController
+
+class GalleryActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ setContent {
+ val isSystemInDarkTheme = isSystemInDarkTheme()
+ var isDarkTheme by remember { mutableStateOf(isSystemInDarkTheme) }
+ val onChangeTheme = { isDarkTheme = !isDarkTheme }
+
+ val systemUiController = rememberSystemUiController()
+ val useDarkIcons = !isDarkTheme
+ SideEffect {
+ systemUiController.setSystemBarsColor(
+ color = Color.Transparent,
+ darkIcons = useDarkIcons,
+ )
+ }
+
+ GalleryApp(isDarkTheme, onChangeTheme)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
new file mode 100644
index 000000000000..f7d311b288be
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -0,0 +1,127 @@
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import com.android.systemui.compose.theme.SystemUITheme
+
+enum class Screen {
+ Home,
+ Typography,
+ Colors,
+ ExampleFeature,
+}
+
+/** The main content of the app, that shows the [HomeScreen] by default. */
+@Composable
+private fun MainContent() {
+ Box(Modifier.fillMaxSize()) {
+ val navController = rememberNavController()
+ NavHost(
+ navController = navController,
+ startDestination = Screen.Home.name,
+ ) {
+ composable(Screen.Home.name) {
+ HomeScreen(
+ onScreenSelected = { navController.navigate(it.name) },
+ )
+ }
+ composable(Screen.Typography.name) { TypographyScreen() }
+ composable(Screen.Colors.name) { ColorsScreen() }
+ composable(Screen.ExampleFeature.name) { ExampleFeatureScreen() }
+ }
+ }
+}
+
+/**
+ * The top-level composable shown when starting the app. This composable always shows a
+ * [ConfigurationControls] at the top of the screen, above the [MainContent].
+ */
+@Composable
+fun GalleryApp(
+ isDarkTheme: Boolean,
+ onChangeTheme: () -> Unit,
+) {
+ val systemFontScale = LocalDensity.current.fontScale
+ var fontScale: FontScale by remember {
+ mutableStateOf(
+ FontScale
+ .values()
+ .firstOrNull { it.scale == systemFontScale }
+ ?: FontScale.Normal
+ )
+ }
+ val context = LocalContext.current
+ val density = Density(context.resources.displayMetrics.density, fontScale.scale)
+ val onChangeFontScale = {
+ fontScale = when (fontScale) {
+ FontScale.Small -> FontScale.Normal
+ FontScale.Normal -> FontScale.Big
+ FontScale.Big -> FontScale.Bigger
+ FontScale.Bigger -> FontScale.Small
+ }
+ }
+
+ val systemLayoutDirection = LocalLayoutDirection.current
+ var layoutDirection by remember { mutableStateOf(systemLayoutDirection) }
+ val onChangeLayoutDirection = {
+ layoutDirection = when (layoutDirection) {
+ LayoutDirection.Ltr -> LayoutDirection.Rtl
+ LayoutDirection.Rtl -> LayoutDirection.Ltr
+ }
+ }
+
+ CompositionLocalProvider(
+ LocalDensity provides density,
+ LocalLayoutDirection provides layoutDirection,
+ ) {
+ SystemUITheme(isDarkTheme) {
+ Surface(
+ Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background,
+ ) {
+ Column(
+ Modifier
+ .fillMaxSize()
+ .systemBarsPadding()
+ .padding(16.dp)
+ ) {
+ ConfigurationControls(
+ isDarkTheme,
+ fontScale,
+ layoutDirection,
+ onChangeTheme,
+ onChangeLayoutDirection,
+ onChangeFontScale,
+ )
+
+ Spacer(Modifier.height(4.dp))
+
+ MainContent()
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/HomeScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/HomeScreen.kt
new file mode 100644
index 000000000000..d0f265c07177
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/HomeScreen.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+/** The home screen shown when starting the app. */
+@Composable
+fun HomeScreen(onScreenSelected: (Screen) -> Unit) {
+ LazyColumn(
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Screen.values()
+ .filter { it != Screen.Home }
+ .forEach { screen ->
+ item {
+ Surface(
+ Modifier.fillMaxWidth(),
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ shape = CircleShape,
+ ) {
+ Column(
+ Modifier
+ .clickable { onScreenSelected(screen) }
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text(screen.name)
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt
new file mode 100644
index 000000000000..32191916547d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.TextOverflow
+
+/** The screen that shows the Material text styles. */
+@Composable
+fun TypographyScreen() {
+ val typography = MaterialTheme.typography
+
+ Column(
+ Modifier
+ .fillMaxSize()
+ .horizontalScroll(rememberScrollState())
+ .verticalScroll(rememberScrollState()),
+ ) {
+ FontLine("displayLarge", typography.displayLarge)
+ FontLine("displayMedium", typography.displayMedium)
+ FontLine("displaySmall", typography.displaySmall)
+ FontLine("headlineLarge", typography.headlineLarge)
+ FontLine("headlineMedium", typography.headlineMedium)
+ FontLine("headlineSmall", typography.headlineSmall)
+ FontLine("titleLarge", typography.titleLarge)
+ FontLine("titleMedium", typography.titleMedium)
+ FontLine("titleSmall", typography.titleSmall)
+ FontLine("bodyLarge", typography.bodyLarge)
+ FontLine("bodyMedium", typography.bodyMedium)
+ FontLine("bodySmall", typography.bodySmall)
+ FontLine("labelLarge", typography.labelLarge)
+ FontLine("labelMedium", typography.labelMedium)
+ FontLine("labelSmall", typography.labelSmall)
+ }
+}
+
+@Composable
+private fun FontLine(name: String, style: TextStyle) {
+ Text(
+ "$name (${style.fontSize}/${style.lineHeight}, W${style.fontWeight?.weight})",
+ style = style,
+ maxLines = 1,
+ overflow = TextOverflow.Visible,
+ )
+}
diff --git a/packages/SystemUI/compose/gallery/tests/Android.bp b/packages/SystemUI/compose/gallery/tests/Android.bp
new file mode 100644
index 000000000000..3e01f7d2c431
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_test {
+ name: "SystemUIComposeGalleryTests",
+ manifest: "AndroidManifest.xml",
+ test_suites: ["device-tests"],
+ sdk_version: "current",
+ certificate: "platform",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "SystemUIComposeGalleryLib",
+
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui-test-junit4",
+ "androidx.compose.ui_ui-test-manifest",
+ ],
+
+ kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml b/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..5eeb3ad24e5a
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.compose.gallery.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.systemui.compose.gallery.tests"
+ android:label="Tests for SystemUIComposeGallery"/>
+
+</manifest> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt b/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
new file mode 100644
index 000000000000..6fb1674d3f16
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.compose.gallery
+
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.systemui.compose.theme.SystemUITheme
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ScreenshotsTests {
+ @get:Rule
+ val composeRule = createComposeRule()
+
+ @Test
+ fun exampleFeatureScreenshotTest() {
+ // TODO(b/230832101): Wire this with the screenshot diff testing infra. We should reuse the
+ // configuration of the features in the gallery app to populate the UIs.
+ composeRule.setContent {
+ SystemUITheme {
+ ExampleFeatureScreen()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 3058d9466121..bef61b867f7d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -23,7 +23,9 @@ import java.util.TimeZone;
/**
* Plugin used to replace main clock in keyguard.
+ * @deprecated Migrating to ClockProviderPlugin
*/
+@Deprecated
@ProvidesInterface(action = ClockPlugin.ACTION, version = ClockPlugin.VERSION)
public interface ClockPlugin extends Plugin {
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml
new file mode 100644
index 000000000000..538f3284a301
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml
@@ -0,0 +1,725 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="7.062"
+ android:valueTo="8.578"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateX"
+ android:startOffset="28"
+ android:valueFrom="8.578"
+ android:valueTo="-1.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateX"
+ android:startOffset="248"
+ android:valueFrom="-1.789"
+ android:valueTo="-7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="3.312"
+ android:valueTo="2.016"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateY"
+ android:startOffset="28"
+ android:valueFrom="2.016"
+ android:valueTo="-8.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateY"
+ android:startOffset="248"
+ android:valueFrom="-8.789"
+ android:valueTo="-3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="180"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="rotation"
+ android:startOffset="28"
+ android:valueFrom="90"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="rotation"
+ android:startOffset="193"
+ android:valueFrom="90"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="-7"
+ android:valueTo="-8.859"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateX"
+ android:startOffset="28"
+ android:valueFrom="-8.859"
+ android:valueTo="1.69"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateX"
+ android:startOffset="248"
+ android:valueFrom="1.69"
+ android:valueTo="7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="-3.594"
+ android:valueTo="-1.922"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateY"
+ android:startOffset="28"
+ android:valueFrom="-1.922"
+ android:valueTo="8.627"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateY"
+ android:startOffset="248"
+ android:valueFrom="8.627"
+ android:valueTo="3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="360"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="rotation"
+ android:startOffset="28"
+ android:valueFrom="270"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="rotation"
+ android:startOffset="193"
+ android:valueFrom="270"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="rotation"
+ android:startOffset="248"
+ android:valueFrom="180"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="66"
+ android:propertyName="pathData"
+ android:startOffset="28"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="72"
+ android:propertyName="pathData"
+ android:startOffset="94"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="166"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="pathData"
+ android:startOffset="193"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="290"
+ android:valueFrom="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueTo="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="317"
+ android:valueFrom="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueTo="M5.94 -2.52 C5.94,-2.52 5.94,-2.51 5.94,-2.51 C5.94,-2.51 5.93,-2.52 5.93,-2.52 C5.93,-2.52 4.53,-1.12 4.53,-1.12 C4.53,-1.12 4.55,-1.11 4.55,-1.11 C4.55,-1.11 4.53,-1.13 4.53,-1.13 C4.53,-1.13 4.55,-1.09 4.55,-1.09 C4.55,-1.09 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 5.94,-2.52 5.94,-2.52 C5.94,-2.52 5.94,-2.52 5.94,-2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="66"
+ android:propertyName="pathData"
+ android:startOffset="28"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="72"
+ android:propertyName="pathData"
+ android:startOffset="94"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="166"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="pathData"
+ android:startOffset="193"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="290"
+ android:valueFrom="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueTo="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="317"
+ android:valueFrom="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueTo="M-5.94 2.52 C-5.94,2.52 -5.94,2.51 -5.94,2.51 C-5.94,2.51 -5.93,2.52 -5.93,2.52 C-5.93,2.52 -4.53,1.12 -4.53,1.12 C-4.53,1.12 -4.55,1.11 -4.55,1.11 C-4.55,1.11 -4.53,1.13 -4.53,1.13 C-4.53,1.13 -4.55,1.09 -4.55,1.09 C-4.55,1.09 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -5.94,2.52 -5.94,2.52 C-5.94,2.52 -5.94,2.52 -5.94,2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="61"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="61"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="143"
+ android:propertyName="pathData"
+ android:startOffset="88"
+ android:valueFrom="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueTo="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="232"
+ android:valueFrom="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueTo="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueTo="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -8.52,-3.53 -8.52,-3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="61"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="61"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="143"
+ android:propertyName="pathData"
+ android:startOffset="88"
+ android:valueFrom="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueTo="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="232"
+ android:valueFrom="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueTo="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueTo="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 8.52,3.53 8.52,3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="683"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G_N_1_T_0"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <group
+ android:name="_R_G_L_2_G_T_1"
+ android:rotation="180"
+ android:translateX="7.062"
+ android:translateY="3.312">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_1_T_0"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:rotation="360"
+ android:translateX="-7"
+ android:translateY="-3.594">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml
new file mode 100644
index 000000000000..bd67d9f8dbaa
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml
@@ -0,0 +1,781 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="367"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="45"
+ android:propertyName="pathData"
+ android:startOffset="59"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="103"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="pathData"
+ android:startOffset="121"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="26"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="181"
+ android:valueFrom="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueTo="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="52"
+ android:propertyName="pathData"
+ android:startOffset="198"
+ android:valueFrom="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueTo="M5.94 -2.52 C5.94,-2.52 5.94,-2.51 5.94,-2.51 C5.94,-2.51 5.93,-2.52 5.93,-2.52 C5.93,-2.52 4.53,-1.12 4.53,-1.12 C4.53,-1.12 4.55,-1.11 4.55,-1.11 C4.55,-1.11 4.53,-1.13 4.53,-1.13 C4.53,-1.13 4.55,-1.09 4.55,-1.09 C4.55,-1.09 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 5.94,-2.52 5.94,-2.52 C5.94,-2.52 5.94,-2.52 5.94,-2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="367"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="45"
+ android:propertyName="pathData"
+ android:startOffset="59"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="103"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="pathData"
+ android:startOffset="121"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="26"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="181"
+ android:valueFrom="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueTo="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="52"
+ android:propertyName="pathData"
+ android:startOffset="198"
+ android:valueFrom="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueTo="M-5.94 2.52 C-5.94,2.52 -5.94,2.51 -5.94,2.51 C-5.94,2.51 -5.93,2.52 -5.93,2.52 C-5.93,2.52 -4.53,1.12 -4.53,1.12 C-4.53,1.12 -4.55,1.11 -4.55,1.11 C-4.55,1.11 -4.53,1.13 -4.53,1.13 C-4.53,1.13 -4.55,1.09 -4.55,1.09 C-4.55,1.09 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -5.94,2.52 -5.94,2.52 C-5.94,2.52 -5.94,2.52 -5.94,2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="38"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="38"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="90"
+ android:propertyName="pathData"
+ android:startOffset="55"
+ android:valueFrom="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueTo="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="10"
+ android:propertyName="pathData"
+ android:startOffset="145"
+ android:valueFrom="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueTo="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueTo="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -8.52,-3.53 -8.52,-3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="38"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="38"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="90"
+ android:propertyName="pathData"
+ android:startOffset="55"
+ android:valueFrom="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueTo="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="10"
+ android:propertyName="pathData"
+ android:startOffset="145"
+ android:valueFrom="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueTo="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueTo="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 8.52,3.53 8.52,3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="-7"
+ android:valueTo="-8.859"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateX"
+ android:startOffset="17"
+ android:valueFrom="-8.859"
+ android:valueTo="1.734"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateX"
+ android:startOffset="155"
+ android:valueFrom="1.734"
+ android:valueTo="7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="-3.594"
+ android:valueTo="-1.922"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateY"
+ android:startOffset="17"
+ android:valueFrom="-1.922"
+ android:valueTo="8.671"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateY"
+ android:startOffset="155"
+ android:valueFrom="8.671"
+ android:valueTo="3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="360"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="103"
+ android:propertyName="rotation"
+ android:startOffset="17"
+ android:valueFrom="270"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="rotation"
+ android:startOffset="121"
+ android:valueFrom="270"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="rotation"
+ android:startOffset="155"
+ android:valueFrom="180"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="7.062"
+ android:valueTo="8.578"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateX"
+ android:startOffset="17"
+ android:valueFrom="8.578"
+ android:valueTo="-1.656"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateX"
+ android:startOffset="155"
+ android:valueFrom="-1.656"
+ android:valueTo="-7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="3.312"
+ android:valueTo="2.016"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateY"
+ android:startOffset="17"
+ android:valueFrom="2.016"
+ android:valueTo="-8.656"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateY"
+ android:startOffset="155"
+ android:valueFrom="-8.656"
+ android:valueTo="-3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="180"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="103"
+ android:propertyName="rotation"
+ android:startOffset="17"
+ android:valueFrom="90"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="rotation"
+ android:startOffset="121"
+ android:valueFrom="90"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c " />
+ <path
+ android:name="_R_G_L_2_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c " />
+ <path
+ android:name="_R_G_L_2_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c " />
+ <path
+ android:name="_R_G_L_2_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:rotation="360"
+ android:translateX="-7"
+ android:translateY="-3.594">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="180"
+ android:translateX="7.062"
+ android:translateY="3.312">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml
new file mode 100644
index 000000000000..17a76116db25
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c "/>
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="14.125"
+ android:translateY="12"
+ android:pivotX="-9.109"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 -1.5 C-8.26,-1.5 -7.59,-0.83 -7.59,0 C-7.59,0.83 -8.26,1.5 -9.09,1.5 C-9.91,1.5 -10.59,0.83 -10.59,0 C-10.59,-0.83 -9.91,-1.5 -9.09,-1.5c "/>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="14.125"
+ android:translateY="12"
+ android:pivotX="4.875"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 -1.5 C5.75,-1.5 6.42,-0.83 6.42,0 C6.42,0.83 5.75,1.5 4.92,1.5 C4.09,1.5 3.42,0.83 3.42,0 C3.42,-0.83 4.09,-1.5 4.92,-1.5c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr
+ name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml
new file mode 100644
index 000000000000..2dba48cf155d
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="-9.109"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 -1.5 C-8.26,-1.5 -7.59,-0.83 -7.59,0 C-7.59,0.83 -8.26,1.5 -9.09,1.5 C-9.91,1.5 -10.59,0.83 -10.59,0 C-10.59,-0.83 -9.91,-1.5 -9.09,-1.5c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="4.875"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 -1.5 C5.75,-1.5 6.42,-0.83 6.42,0 C6.42,0.83 5.75,1.5 4.92,1.5 C4.09,1.5 3.42,0.83 3.42,0 C3.42,-0.83 4.09,-1.5 4.92,-1.5c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml
new file mode 100644
index 000000000000..3697769cfa34
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1017"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M4.56 2.33 C4.56,2.33 2.24,0.01 2.24,0.01 C2.24,0.01 4.57,-2.31 4.57,-2.31 C4.84,-1.59 5,-0.82 5,0 C5,0.82 4.84,1.61 4.56,2.33c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M6.27 -4.03 C6.27,-4.03 7.53,-5.29 7.53,-5.29 C8.46,-3.77 9,-1.99 9.01,-0.1 C9.01,1.85 8.44,3.67 7.47,5.21 C7.47,5.21 6.27,4.01 6.27,4.01 C6.89,2.81 7.25,1.44 7.25,-0.01 C7.25,-1.46 6.9,-2.82 6.27,-4.03c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.6 -2.33 C-8.6,-2.33 -6.28,-0.01 -6.28,-0.01 C-6.28,-0.01 -8.61,2.31 -8.61,2.31 C-8.88,1.59 -9.04,0.82 -9.04,0 C-9.04,-0.82 -8.88,-1.61 -8.6,-2.33c " />
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-10.31 4.03 C-10.31,4.03 -11.57,5.29 -11.57,5.29 C-12.5,3.77 -13.04,1.99 -13.05,0.1 C-13.05,-1.85 -12.48,-3.67 -11.51,-5.21 C-11.51,-5.21 -10.31,-4.01 -10.31,-4.01 C-10.93,-2.81 -11.29,-1.44 -11.29,0.01 C-11.29,1.46 -10.94,2.82 -10.31,4.03c " />
+ <path
+ android:name="_R_G_L_0_G_D_5_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_6_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 625ffd3aa3ec..deab61088d56 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -25,11 +25,11 @@
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
<item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
- <item name="android:textSize">14dp</item>
+ <item name="android:textSize">16sp</item>
<item name="android:background">@drawable/kg_emergency_button_background</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:paddingLeft">12dp</item>
- <item name="android:paddingRight">12dp</item>
+ <item name="android:paddingLeft">26dp</item>
+ <item name="android:paddingRight">26dp</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="NumPadKey" parent="Theme.SystemUI">
diff --git a/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml b/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml
new file mode 100644
index 000000000000..5fd7ee29d838
--- /dev/null
+++ b/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+ <corners android:radius="@dimen/broadcast_dialog_btn_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 779ab816d925..9b43cf64f116 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="@color/media_dialog_item_main_content"
+ android:fillColor="@color/media_dialog_inactive_item_main_content"
android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_screen_saver.xml b/packages/SystemUI/res/drawable/ic_qs_screen_saver.xml
new file mode 100644
index 000000000000..263a3d1c894c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_screen_saver.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2022 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M5,15H19L14.5,9L11,13.5L8.5,10.5ZM6,21Q5.575,21 5.287,20.712Q5,20.425 5,20V19H3Q2.175,19 1.588,18.413Q1,17.825 1,17V6Q1,5.175 1.588,4.588Q2.175,4 3,4H21Q21.825,4 22.413,4.588Q23,5.175 23,6V17Q23,17.825 22.413,18.413Q21.825,19 21,19H19V20Q19,20.425 18.712,20.712Q18.425,21 18,21ZM3,17H21Q21,17 21,17Q21,17 21,17V6Q21,6 21,6Q21,6 21,6H3Q3,6 3,6Q3,6 3,6V17Q3,17 3,17Q3,17 3,17ZM3,17Q3,17 3,17Q3,17 3,17V6Q3,6 3,6Q3,6 3,6Q3,6 3,6Q3,6 3,6V17Q3,17 3,17Q3,17 3,17Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 3a08a7111d9a..41123c84ded1 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -16,19 +16,13 @@
* limitations under the License.
*/
-->
-<ripple
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:color="?android:attr/textColorPrimary">
- <item>
- <shape
- android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_width"
- android:height="@dimen/keyguard_affordance_height"/>
- <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
- </shape>
- </item>
-</ripple>
-
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <size
+ android:width="@dimen/keyguard_affordance_width"
+ android:height="@dimen/keyguard_affordance_height"/>
+ <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 0599e239a9ee..05c635833441 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_item_main_content"
+ android:fillColor="@color/media_dialog_inactive_item_main_content"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/settings_input_antenna.xml b/packages/SystemUI/res/drawable/settings_input_antenna.xml
new file mode 100644
index 000000000000..f2adcaf069ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settings_input_antenna.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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="24dp"
+ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
+ android:tint="?android:attr/textColorSecondary">
+ <path android:fillColor="#FF000000"
+ android:pathData="M9,22.4 L7.6,21 11,17.6V14.3Q10.325,14 9.913,13.375Q9.5,12.75 9.5,12Q9.5,10.95 10.225,10.225Q10.95,9.5 12,9.5Q13.05,9.5 13.775,10.225Q14.5,10.95 14.5,12Q14.5,12.75 14.088,13.375Q13.675,14 13,14.3V17.6L16.4,21L15,22.4L12,19.4ZM5,12Q5,9.05 7.05,7.025Q9.1,5 12,5Q14.9,5 16.95,7.025Q19,9.05 19,12H17Q17,9.925 15.538,8.462Q14.075,7 12,7Q9.925,7 8.463,8.462Q7,9.925 7,12ZM1,12Q1,9.7 1.863,7.7Q2.725,5.7 4.225,4.212Q5.725,2.725 7.725,1.862Q9.725,1 12,1Q14.275,1 16.275,1.862Q18.275,2.725 19.775,4.212Q21.275,5.7 22.138,7.7Q23,9.7 23,12H21Q21,10.125 20.288,8.487Q19.575,6.85 18.35,5.625Q17.125,4.4 15.488,3.7Q13.85,3 12,3Q10.15,3 8.512,3.7Q6.875,4.4 5.65,5.625Q4.425,6.85 3.712,8.487Q3,10.125 3,12Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/broadcast_dialog.xml b/packages/SystemUI/res/layout/broadcast_dialog.xml
new file mode 100644
index 000000000000..5ba2afe5b172
--- /dev/null
+++ b/packages/SystemUI/res/layout/broadcast_dialog.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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:id="@+id/dialog_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/dialog_icon"
+ android:layout_width="@dimen/broadcast_dialog_icon_size"
+ android:layout_height="@dimen/broadcast_dialog_icon_size"
+ android:layout_marginTop="@dimen/broadcast_dialog_icon_margin_top"
+ android:layout_marginBottom="@dimen/broadcast_dialog_title_img_margin_top"
+ android:layout_gravity="center"
+ android:src="@drawable/settings_input_antenna"/>
+
+ <TextView
+ style="@style/BroadcastDialogTitleStyle"
+ android:id="@+id/dialog_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+
+ <TextView
+ style="@style/BroadcastDialogBodyStyle"
+ android:id="@+id/dialog_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/broadcast_dialog_margin"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/switch_broadcast"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/change_output"
+ android:text="@string/bt_le_audio_broadcast_dialog_different_output"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:id="@+id/cancel"
+ android:text="@android:string/cancel"
+ style="@style/BroadcastDialogButtonStyle"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
deleted file mode 100644
index 0a1730a72920..000000000000
--- a/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2016 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
- -->
-
-<com.android.systemui.statusbar.policy.EmergencyCryptkeeperText
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/emergency_cryptkeeper_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:paddingStart="6dp"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:gravity="center_vertical|start"
- /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 7785a098a0eb..5b1ec7f59b55 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -129,17 +129,17 @@
android:layout_height="64dp"
android:layout_gravity="end|center"
android:gravity="center_vertical">
- <CheckBox
- android:id="@+id/check_box"
- android:focusable="false"
- android:importantForAccessibility="no"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginEnd="16dp"
- android:layout_gravity="end"
- android:button="@drawable/ic_circle_check_box"
- android:visibility="gone"
- />
+ <CheckBox
+ android:id="@+id/check_box"
+ android:focusable="false"
+ android:importantForAccessibility="no"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginEnd="16dp"
+ android:layout_gravity="end"
+ android:button="@drawable/ic_circle_check_box"
+ android:visibility="gone"
+ />
</LinearLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index deab1ebd6507..f560e6107fb7 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -141,11 +141,4 @@
</com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
- <ViewStub
- android:id="@+id/emergency_cryptkeeper_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/emergency_cryptkeeper_text"
- />
-
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index ae16e5c919c4..7c755e546589 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -77,8 +77,7 @@
android:layout_height="@dimen/magnification_drag_view_size"
android:layout_margin="@dimen/magnification_inner_border_margin"
android:layout_gravity="right|bottom"
- android:paddingEnd="@dimen/magnifier_drag_handle_padding"
- android:paddingBottom="@dimen/magnifier_drag_handle_padding"
+ android:padding="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:importantForAccessibility="no"
android:src="@drawable/ic_move_magnification"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5c1a6b580cb8..07cb7dfeb840 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestig"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestig om te voltooi"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Ontsluit met gesig. Druk die ontsluitikoon om voort te gaan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontsluit met gesig. Druk om voort te gaan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesig is herken. Druk om voort te gaan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesig is herken. Druk die ontsluitikoon om voort te gaan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Gestaaf"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gebruik PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gebruik patroon"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outo-draai"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Sluimerskerm"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratoegang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofoontoegang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beskikbaar"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swiep op om oop te maak"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Druk die onsluitikoon om oop te maak"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Ontsluit met gesig. Druk die ontsluitikoon om oop te maak."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ontsluit met gesig. Druk om oop te maak."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gesig is herken. Druk om oop te maak."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gesig is herken. Druk die ontsluitikoon om oop te maak."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Beweeg links"</item>
<item msgid="5558598599408514296">"Beweeg af"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, gaan voort"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gasmodus"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Jy is in gasmodus"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"As ’n nuwe gebruiker bygevoeg word, sal gasmodus verlaat word en sal alle programme en data in die huidige gastesessie uitgevee word."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerlimiet is bereik"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Jy kan tot <xliff:g id="COUNT">%d</xliff:g> gebruikers byvoeg.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Opletberigte"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skermkiekies"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Algemene boodskappe"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Kitsprogramme"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Opstelling"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Berging"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wenke"</string>
<string name="instant_apps" msgid="8337185853050247304">"Kitsprogramme"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ligging"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"skermopname"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Maak die program oop om hierdie sessie uit te saai."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende program"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beskikbare toestelle vir oudio-uitsette."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Saai uit"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mense in jou omtrek met versoenbare Bluetooth-toestelle kan na die media luister wat jy uitsaai"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klaar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieer"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Van <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Maak gekopieerde teks toe"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Maak kopieer-UI toe"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Wysig gekopieerde teks"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Wysig gekopieerde prent"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Stuur na toestel in die omtrek"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera en mikrofoon is af"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitsaai"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Saai <xliff:g id="SWITCHAPP">%1$s</xliff:g> uit"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Verander uitvoer"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Onbekend"</string>
</resources>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index 93d26e8f1f83..e60f23329212 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Af"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Onbeskikbaar"</item>
+ <item msgid="8014986104355098744">"Af"</item>
+ <item msgid="5966994759929723339">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 5176f7cdb54b..bf265969c2e6 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ተረጋግጧል"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ለማጠናቀቅ አረጋግጥን መታ ያድርጉ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"በመልክ ተከፍቷል። ለመቀጠል የመክፈቻ አዶውን ይጫኑ።"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"በመልክ ተከፍቷል። ለመቀጠል ይጫኑ።"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"መልክ ተለይቶ ታውቋል። ለመቀጠል ይጫኑ።"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"መልክ ተለይቶ ታውቋል። ለመቀጠል የመክፈቻ አዶውን ይጫኑ።"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"የተረጋገጠ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ፒን ይጠቀሙ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ሥርዓተ ጥለትን ተጠቀም"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"የማያ ገጽ ማቆያ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"የካሜራ መዳረሻ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"የማይክሮፎን መዳረሻ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ይገኛል"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ለመክፈት በጣት ወደ ላይ ጠረግ ያድርጉ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ለመክፈት የመክፈቻ አዶውን ይጫኑ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"በመልክ ተከፍቷል። ለመክፈት የመክፈቻ አዶውን ይጫኑ።"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"በመልክ ተከፍቷል። ለመክፈት ይጫኑ።"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"መልክ ተለይቶ ታውቋል። ለመክፈት ይጫኑ።"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"መልክ ተለይቶ ታውቋል። ለመክፈት የመክፈቻ አዶውን ይጫኑ።"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ወደ ግራ ውሰድ"</item>
<item msgid="5558598599408514296">"ወደ ታች ውሰድ"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"አዎ፣ ቀጥል"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"የእንግዳ ሁነታ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"በእንግዳ ሁኔታ ውስጥ ነዎት"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"አዲስ ተጠቃሚ ማከል ከእንግዳ ሁነታ ወጥቶ ሁሉንም መተግበሪያዎች እና ውሂብ አሁን ካለው የእንግዳ ክፍለ ጊዜ ይሰርዛል።"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"የተጠቃሚ ገደብ ላይ ተደርሷል"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ተጠቃሚዎች ብቻ ናቸው ሊፈጠሩ የሚችሉት።</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ማንቂያዎች"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ባትሪ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ቅጽበታዊ ገጽ እይታዎች"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"አጠቃላይ መልዕክቶች"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"ቅጽበታዊ መተግበሪያዎች"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ውቅረት"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ማከማቻ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ፍንጮች"</string>
<string name="instant_apps" msgid="8337185853050247304">"የቅጽበት መተግበሪያዎች"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ካሜራ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"አካባቢ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ማይክሮፎን"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ማያን መቅረጽ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ይህን ክፍለ ጊዜ cast ለማድረግ፣ እባክዎ መተግበሪያውን ይክፈቱ።"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"የማይታወቅ መተግበሪያ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Cast ማድረግ አቁም"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ለኦዲዮ ውጽዓት ተገኚ የሆኑ መሣሪያዎች"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ማሰራጨት እንዴት እንደሚሠራ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ስርጭት"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ተኳሃኝ የብሉቱዝ መሣሪያዎች ያላቸው በአቅራቢያዎ ያሉ ሰዎች እርስዎ እያሰራጩት ያሉትን ሚዲያ ማዳመጥ ይችላሉ"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ተከናውኗል"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ተቀድቷል"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ከ<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"የተቀዳ ጽሑፍን አሰናብት"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ዩአይ ቅዳን አሰናብት"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"የተቀዳ ጽሁፍ አርትዕ ያድርጉ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"የተቀዳ ምስል አርትዕ ያድርጉ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"በአቅራቢያ ወዳለ መሳሪያ ይላኩ"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ማንቂያ ተቀናብሯል"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ካሜራ እና ማይክሮፎን ጠፍተዋል"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"በማሰራጨት ላይ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ማሰራጨት ይቁም?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>ን ካሰራጩ ወይም ውፅዓትን ከቀየሩ የአሁኑ ስርጭትዎ ይቆማል"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ያሰራጩ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ውፅዓትን ይቀይሩ"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ያልታወቀ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 12be1ae2fd22..bbf2d2385f05 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"አጥፋ"</item>
<item msgid="460891964396502657">"አብራ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"አይገኝም"</item>
+ <item msgid="8014986104355098744">"ጠፍቷል"</item>
+ <item msgid="5966994759929723339">"በርቷል"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8a6fa77d64b4..521a762e2c1f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"فُتح القفل عندما تمّ التعرّف على وجهك. للمتابعة، اضغط على رمز فتح القفل."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط للمتابعة."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"تم التعرّف على الوجه. اضغط للمتابعة."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"تم التعرّف على الوجه. للمتابعة، اضغط على رمز فتح القفل."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"مصادقة"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استخدام رقم تعريف شخصي"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استخدام نقش"</string>
@@ -227,6 +230,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"شاشة الاستراحة"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"الوصول إلى الكاميرا"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول إلى الميكروفون"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"متاح"</string>
@@ -321,6 +325,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"يمكنك الفتح بالتمرير سريعًا لأعلى."</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"اضغط على رمز فتح القفل لفتح قفل الشاشة."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"فُتح القفل عندما تمّ التعرّف على وجهك. اضغط على رمز فتح القفل لفتحه."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط لفتح الجهاز."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"تم التعرّف على الوجه. اضغط لفتح الجهاز."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"تم التعرّف على الوجه. اضغط على رمز فتح القفل لفتح الجهاز."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"نقل لليسار"</item>
<item msgid="5558598599408514296">"نقل للأسفل"</item>
@@ -353,6 +360,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"نعم، متابعة"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"وضع الضيف"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"أنت تستخدِم وضع الضيف."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ستؤدي إضافة مُستخدِم جديد إلى الخروج من وضع الضيف وحذف كل التطبيقات والبيانات من جلسة الضيف الحالية."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"تم الوصول إلى أقصى عدد للمستخدمين"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="zero">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدم.</item>
@@ -711,7 +721,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"التنبيهات"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"البطارية"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"لقطات الشاشة"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"رسائل عامة"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"التطبيقات الفورية"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"عملية الإعداد"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"مساحة التخزين"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"تلميحات"</string>
<string name="instant_apps" msgid="8337185853050247304">"التطبيقات الفورية"</string>
@@ -759,7 +770,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"الكاميرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"الموقع"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"الميكروفون"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"تسجيل محتوى الشاشة"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string>
@@ -867,10 +877,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"لبث هذه الجلسة، يُرجى فتح التطبيق"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"تطبيق غير معروف"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"إيقاف البث"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"الأجهزة المتاحة لإخراج الصوت"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"البث"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"يمكن للأشخاص القريبين منك الذين لديهم أجهزة متوافقة تتضمّن بلوتوث الاستماع إلى الوسائط التي تبثها."</string>
@@ -966,7 +972,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"تم"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"تم النسخ."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"من <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"إغلاق حافظة النص المنسوخ"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"إغلاق واجهة مستخدم النسخ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"تعديل النص المنسوخ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"تعديل الصورة المنسوخة"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"الإرسال إلى جهاز مجاور"</string>
@@ -982,4 +988,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"تم ضبط المنبه."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"الكاميرا والميكروفون غير مفعّلين."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"البث"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغيير جهاز الإخراج"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"غير معروف"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index b4fb760f5e65..44b58f964ce9 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"غير مفعّل"</item>
<item msgid="460891964396502657">"مفعّل"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"غير متوفّرة"</item>
+ <item msgid="8014986104355098744">"غير مفعّلة"</item>
+ <item msgid="5966994759929723339">"مفعَّلة"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 9aea4dee1542..f70705b644ff 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"নিশ্চিত কৰিলে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূৰ্ণ কৰিবলৈ নিশ্চিত কৰক-ত টিপক"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যৱহাৰ কৰক"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"আৰ্হি ব্যৱহাৰ কৰক"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"স্ক্ৰীন ছেভাৰ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"কেমেৰাৰ এক্সেছ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"মাইকৰ এক্সেছ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"উপলব্ধ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"খুলিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"খুলিবলৈ আনলক কৰক চিহ্নটোত টিপক"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। খুলিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। খুলিবলৈ টিপক।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। খুলিবলৈ টিপক।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। খুলিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"বাওঁফাললৈ নিয়ক"</item>
<item msgid="5558598599408514296">"তললৈ নিয়ক"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হয়, অব্যাহত ৰাখক"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"অতিথি ম’ড"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"আপুনি অতিথি ম’ডত আছে"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"এগৰাকী নতুন ব্যৱহাৰকাৰীক যোগ দিয়াটোৱে অতিথি ম’ডৰ পৰা বাহিৰ কৰিব আৰু বৰ্তমানৰ অতিথিৰ ছেশ্বনটোৰ পৰা আটাইবোৰ এপ্ আৰু ডেটা মচিব।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"অধিকতম ব্যৱহাৰকাৰী সৃষ্টি কৰা হ’ল"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"সতৰ্কবার্তাসমূহ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"বেটাৰী"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"স্ক্ৰীণশ্বটসমূহ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"সাধাৰণ বার্তাসমূহ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"তাৎক্ষণিক এপ্"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ছেটআপ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ষ্ট\'ৰেজ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ইংগিতবোৰ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<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="privacy_type_media_projection" msgid="8136723828804251547">"স্ক্ৰীন ৰেকৰ্ডিং"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই ছেশ্বনটো কাষ্ট কৰিবলৈ, অনুগ্ৰহ কৰি এপ্‌টো খোলক"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজ্ঞাত এপ্"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাষ্ট বন্ধ কৰক"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিঅ\' আউটপুটৰ বাবে উপলব্ধ ডিভাইচ।"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্ৰচাৰ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"সমিল ব্লুটুথ ডিভাইচৰ সৈতে আপোনাৰ নিকটৱৰ্তী স্থানত থকা লোকসকলে আপুনি সম্প্ৰচাৰ কৰা মিডিয়াটো শুনিব পাৰে"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"হ’ল"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"প্ৰতিলিপি কৰা হ’ল"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ পৰা"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"প্ৰতিলিপি কৰা পাঠ অগ্ৰাহ্য কৰক"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"প্ৰতিলিপি কৰা UI অগ্ৰাহ্য কৰক"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"প্ৰতিলিপি কৰা পাঠ সম্পাদনা কৰক"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"প্ৰতিলিপি কৰা প্ৰতিচ্ছবি সম্পাদনা কৰক"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"নিকটৱৰ্তী ডিভাইচলৈ পঠাওক"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"কেমেৰা আৰু মাইক অফ হৈ আছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"সম্প্ৰচাৰণ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্ৰচাৰ কৰক"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট সলনি কৰক"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"অজ্ঞাত"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index 7767cfc6943a..3145341cabe4 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"অফ"</item>
<item msgid="460891964396502657">"অন"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"উপলব্ধ নহয়"</item>
+ <item msgid="8014986104355098744">"অফ আছে"</item>
+ <item msgid="5966994759929723339">"অন আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4f660ef01b19..2f75d7650ec4 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Təsdiqləndi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamaq üçün \"Təsdiq edin\" seçiminə toxunun"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Üzlə kilidi açılıb. \"Kilidi aç\" ikonasına basıb davam edin."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Üz ilə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Üz tanınıb. Davam etmək üçün basın."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb davam edin."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Doğrulandı"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN istifadə edin"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Model istifadə edin"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Məkan"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran qoruyucu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraya giriş"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofona giriş"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Əlçatan"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmaq üçün yuxarı sürüşdürün"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"\"Kilidi aç\" ikonasına basıb açın"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Üzlə kilidi açılıb. \"Kilidi aç\" ikonasına basıb açın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Üz ilə kiliddən çıxarılıb. Açmaq üçün basın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Üz tanınıb. Açmaq üçün basın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb açın."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Sola köçürün"</item>
<item msgid="5558598599408514296">"Aşağı köçürün"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayın"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bəli, davam edin"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Qonaq rejimi"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Qonaq rejimindəsiniz"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Yeni istifadəçi əlavə edildikdə qonaq rejimindən çıxılacaq və cari qonaq sessiyasındakı bütün tətbiqlər və data silinəcək."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"İstifadəçi limitinə çatmısınız"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Maksimum <xliff:g id="COUNT">%d</xliff:g> istifadəçi əlavə edə bilərsiniz.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Xəbərdarlıqlar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batareya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skrinşotlar"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ümumi Mesajlar"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Ani Tətbiqlər"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Ayarlama"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Yaddaş"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Məsləhətlər"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ani Tətbiqlər"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"məkan"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekran çəkimi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu sessiyanı yayımlamaq üçün tətbiqi açın."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Naməlum tətbiq"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayımı dayandırın"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio çıxış üçün əlçatan cihazlar."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Yayım"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Uyğun Bluetooth cihazları olan yaxınlığınızdakı insanlar yayımladığınız medianı dinləyə bilər"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Oldu"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mənbə: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopyalanmış mətni qapadın"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI kopyalanmasını qapadın"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanmış mətni redaktə edin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanmış şəkli redaktə edin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaxınlıqdakı cihaza göndərin"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera və mikrofon deaktivdir"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayım"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlayın"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Nəticəni dəyişdirin"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Naməlum"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index 0311794de3cd..fb745b251bc9 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Deaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Əlçatmazdır"</item>
+ <item msgid="8014986104355098744">"Deaktiv"</item>
+ <item msgid="5966994759929723339">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f4a7bcc392b2..be862971e012 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da biste završili"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Otključano je licem. Pritisnite ikonu otključavanja za nastavak"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano je licem. Pritisnite da biste nastavili."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu otključavanja za nastavak."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Identitet je potvrđen"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite šablon"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar ekrana"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -315,6 +319,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite nagore da biste otvorili"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pritisnite ikonu otključavanja za otvaranje"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Otključano je licem. Pritisnite ikonu otključavanja za otvaranje"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano je licem. Pritisnite da biste otvorili."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice je prepoznato. Pritisnite da biste otvorili."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice prepoznato. Pritisnite ikonu otključavanja za otvaranje."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Pomerite nalevo"</item>
<item msgid="5558598599408514296">"Pomerite nadole"</item>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Režim gosta"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Koristite režim gosta"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dodavanjem novog korisnika izaći ćete iz režima gosta i izbrisaćete sve aplikacije i podatke iz aktuelne sesije gosta."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut maksimalni broj korisnika"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Obaveštenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimci ekrana"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Opšte poruke"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant aplikacije"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Podešavanje"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Memorijski prostor"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Saveti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje ekrana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste prebacivali ovu sesiju, otvorite aplikaciju."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi prebacivanje"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audio izlaz."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcioniše emitovanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitovanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ljudi u blizini sa kompatibilnim Bluetooth uređajima mogu da slušaju medijski sadržaj koji emitujete"</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano je"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog interfejsa"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Izmenite kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Izmenite kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obaveštenje}one{# obaveštenje}few{# obaveštenja}other{# obaveštenja}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitovanje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite da zaustavite emitovanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitujete aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promenite izlaz, aktuelno emitovanje će se zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitujte aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promenite izlaz"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index a057c48bbec9..b69b06419281 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index db88988f7491..9fe46df2e8e0 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Пацверджана"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Націсніце \"Пацвердзіць\", каб завяршыць"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Твар распазнаны. Для працягу націсніце значок разблакіроўкі."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблакіравана распазнаваннем твару. Націсніце для працягу."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Твар распазнаны. Націсніце для працягу."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Твар распазнаны. Для працягу націсніце значок разблакіроўкі."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Распазнана"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Увесці PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Выкарыстаць узор разблакіроўкі"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Экранная застаўка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ да камеры"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ да мікрафона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступ дазволены"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Каб адкрыць, прагарніце ўверх"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Каб адкрыць, націсніце значок разблакіроўкі"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Твар распазнаны. Для адкрыцця націсніце значок разблакіроўкі"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Разблакіравана распазнаваннем твару. Націсніце, каб адкрыць."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Твар распазнаны. Націсніце, каб адкрыць."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Твар распазнаны. Для адкрыцця націсніце значок разблакіроўкі."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Перамясціце палец улева"</item>
<item msgid="5558598599408514296">"Перамясціце палец ніжэй"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, працягнуць"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Гасцявы рэжым"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Вы знаходзіцеся ў гасцявым рэжыме"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Дадаванне новага карыстальніка закрые гасцявы рэжым. Будуць выдалены ўсе праграмы і даныя бягучага гасцявога сеанса."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Дасягнуты ліміт карыстальнікаў"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальніка.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Абвесткі"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Акумулятар"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Здымкі экрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Агульныя паведамленні"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Імгненныя праграмы"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Наладжванне"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Захоўванне"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Падказкі"</string>
<string name="instant_apps" msgid="8337185853050247304">"Імгненныя праграмы"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геалакацыя"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрафон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"запіс экрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Для трансляцыі гэтага сеанса адкрыйце праграму."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невядомая праграма"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спыніць трансляцыю"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Даступныя прылады для вываду аўдыя."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляцыя"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Людзі паблізу, у якіх ёсць прылады з Bluetooth, змогуць праслухваць мультымедыйнае змесціва, якое вы трансліруеце"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Гатова"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скапіравана"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Адхіліць устаўку скапіраванага тэксту"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыць інтэрфейс капіравання"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Змяніць скапіраваны тэкст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Змяніць скапіраваны відарыс"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Адправіць на прыладу паблізу"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера і мікрафон выключаны"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Перадача даных"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Трансляцыя праграмы \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змяненне вываду"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Невядома"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index d2588113f37b..8fb2da26edc2 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Выключана"</item>
<item msgid="460891964396502657">"Уключана"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недаступна"</item>
+ <item msgid="8014986104355098744">"Выключана"</item>
+ <item msgid="5966994759929723339">"Уключана"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 4ec0730cded6..45342953922e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потвърдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Докоснете „Потвърждаване“ за завършване"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Отключено с лице. Натиснете иконата за отключване, за да продължите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отключено с лице. Натиснете, за да продължите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето бе разпознато. Натиснете, за да продължите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето бе разпознато. Продължете чрез иконата за отключване."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Удостоверено"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Използване на ПИН"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Използване на фигура"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматична ориентация"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Скрийнсейвър"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Достъп до камерата"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Достъп до микрофона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Налице"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Прекарайте пръст нагоре, за да отключите"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Натиснете иконата за отключване, за да отворите"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Отключено с лице. Натиснете иконата за отключване, за да отворите."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Отключено с лице. Натиснете за отваряне."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицето бе разпознато. Натиснете за отваряне."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицето бе разпознато. Отворете чрез иконата за отключване."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Преместване наляво"</item>
<item msgid="5558598599408514296">"Преместване надолу"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продължавам"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Режим на гост"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Вие сте в режим на гост"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"С добавянето на нов потребител ще излезете от режима на гост и ще изтриете всички приложения и данни от текущата сесия като гост."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнахте огранич. за потребители"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Можете да добавите до <xliff:g id="COUNT">%d</xliff:g> потребители.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сигнали"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерия"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Екранни снимки"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Общи съобщения"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Мигновени приложения"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Настройване"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Съвети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Мигновени приложения"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камерата"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местополож."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофона"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"записване на екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за увеличение"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да предавате тази сесия, моля, отворете приложението."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестно приложение"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спиране на предаването"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Налични устройства за аудиоизход."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Предаване"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Хората в близост със съвместими устройства с Bluetooth могат да слушат мултимедията, която предавате"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"От <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Отхвърляне на копирания текст"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отхвърляне на ПИ за копиране"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редактиране на копирания текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редактиране на копираното изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Изпращане до устройство в близост"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонът са изключени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Излъчване"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Предаване на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промяна на изхода"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Неизвестно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index da5c325aaa1c..b85133b6bd43 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Изкл."</item>
<item msgid="460891964396502657">"Вкл."</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Не е налице"</item>
+ <item msgid="8014986104355098744">"Изкл."</item>
+ <item msgid="5966994759929723339">"Вкл."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 95f14164e4de..b9072ae26fce 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"কনফার্ম করা হয়েছে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূর্ণ করতে \'কনফার্ম করুন\' বোতামে ট্যাপ করুন"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যাওয়ার জন্য আনলক আইকনে প্রেস করুন।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে আনলক আইকন প্রেস করুন।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"প্রমাণীকৃত"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যবহার করুন"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"প্যাটার্ন ব্যবহার করুন"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"স্ক্রিন সেভার"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ক্যামেরা অ্যাক্সেস"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"মাইক্রোফোন অ্যাক্সেস"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"উপলভ্য"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"খোলার জন্য উপরে সোয়াইপ করুন"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"খোলার জন্য আনলক আইকন প্রেস করুন"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ফেসের সাহায্যে আনলক করা হয়েছে। খোলার জন্য আনলক আইকন প্রেস করুন।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ফেসের সাহায্যে আনলক করা হয়েছে। খোলার জন্য প্রেস করুন।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ফেস শনাক্ত করা হয়েছে। খোলার জন্য প্রেস করুন।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ফেস শনাক্ত করা হয়েছে। খোলার জন্য আনলক আইকন প্রেস করুন।"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"বাঁদিকে সরান"</item>
<item msgid="5558598599408514296">"নিচে নামান"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হ্যাঁ, চালিয়ে যান"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"অতিথি মোড"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"আপনি \'অতিথি মোড\' ব্যবহার করছেন"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"নতুন ব্যবহারকারী যোগ করার মাধ্যমে \'অতিথি মোড\' ছেড়ে বেরিয়ে আসতে পারবেন এবং বর্তমান অতিথি সেশন থেকে সব অ্যাপ ও ডেটা মুছে যাবে।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"আর কোনও প্রোফাইল যোগ করা যাবে না"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">আপনি <xliff:g id="COUNT">%d</xliff:g> জন পর্যন্ত ব্যবহারকারীর প্রোফাইল যোগ করতে পারেন।</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"সতর্কতা"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ব্যাটারি"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"স্ক্রীনশটস"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"সাধারণ বার্তাগুলি"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"সেট-আপ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"স্টোরেজ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"হিন্ট"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ক্যামেরা"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"লোকেশন"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্রোফোন"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"স্ক্রিন রেকর্ডিং"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই সেশন কাস্ট করার জন্য, অ্যাপ খুলুন।"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজানা অ্যাপ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাস্ট করা বন্ধ করুন"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিও আউটপুটের জন্য উপলভ্য ডিভাইস।"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ব্রডকাস্ট কীভাবে কাজ করে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্রচার করুন"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"আশপাশে লোকজন যাদের মানানসই ব্লুটুথ ডিভাইস আছে, তারা আপনার ব্রডকাস্ট করা মিডিয়া শুনতে পারবেন"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"হয়ে গেছে"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"কপি করা হয়েছে"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> থেকে"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"কপি করা টেক্সট বাতিল করুন"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"কপি করা UI বাতিল করুন"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"কপি করা টেক্সট এডিট করুন"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"কপি করা ছবি এডিট করুন"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"আশেপাশের ডিভাইসে পাঠান"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ক্যামেরা ও মাইক্রোফোন বন্ধ আছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ব্রডকাস্ট করা হচ্ছে"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"আপনি <xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করলে বা আউটপুট পরিবর্তন করলে, আপনার বর্তমান সম্প্রচার বন্ধ হয়ে যাবে"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করুন"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট পরিবর্তন করুন"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"অজানা"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 784d974e2eba..d70afc0f7f4f 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"বন্ধ আছে"</item>
<item msgid="460891964396502657">"চালু আছে"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"অনুপলভ্য"</item>
+ <item msgid="8014986104355098744">"বন্ধ আছে"</item>
+ <item msgid="5966994759929723339">"চালু আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index bdc1553e745d..cb2dcf11ee56 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da završite"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Otključano licem. Pritisnite ikonu za otklj. da nastavite."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano licem. Pritisnite da nastavite."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice prepoznato. Pritisnite da nastavite."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu za otklj. da nastavite."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificirano"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristi PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristi uzorak"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar ekrana"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -315,11 +319,14 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite da otvorite"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pritisnite ikonu za otključavanje da otvorite."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Otključano licem. Pritisnite ikonu za otklj. da otvorite."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano licem. Pritisnite da otvorite."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice prepoznato. Pritisnite da otvorite."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice prepoznato. Pritisnite ikonu za otklj. da otvorite."</string>
<string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Pomjeranje ulijevo"</item>
- <item msgid="5558598599408514296">"Pomjeranje nadolje"</item>
- <item msgid="4844142668312841831">"Pomjeranje udesno"</item>
- <item msgid="5640521437931460125">"Pomjeranje nagore"</item>
+ <item msgid="1901953991150295169">"Pomicanje ulijevo"</item>
+ <item msgid="5558598599408514296">"Pomicanje prema dolje"</item>
+ <item msgid="4844142668312841831">"Pomicanje udesno"</item>
+ <item msgid="5640521437931460125">"Pomicanje prema gore"</item>
</string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite prema gore da pokušate ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Način rada za gosta"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Nalazite se u načinu rada za gosta"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dodavanjem novog korisnika napustit ćete način rada za gosta i izbrisati sve aplikacije i podatke iz trenutne sesije gosta."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut limit za broj korisnika"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Obavještenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimci ekrana"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Opće poruke"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant aplikacije"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Postavljanje"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje ekrana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da emitirate ovu sesiju, otvorite aplikaciju."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audio izlaz."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcionira emitiranje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitirajte"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u vašoj blizini s kompatibilnim Bluetooth uređajima mogu slušati medijske sadržaje koje emitirate"</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopirani korisnički interfejs"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiraj aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promijeni izlaz"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index a057c48bbec9..b69b06419281 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 409105610d89..eb88c05cb42f 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirma per completar"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"S\'ha desbloquejat amb la cara. Prem la icona per continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"S\'ha reconegut la cara. Prem per continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"S\'ha reconegut la cara. Prem la icona per continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticat"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilitza el PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilitza el patró"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Estalvi de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accés a la càmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accés al micròfon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Llisca cap amunt per obrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Prem la icona de desbloqueig per obrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"S\'ha desbloquejat amb la cara. Prem la icona per obrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"S\'ha desbloquejat amb la cara. Prem per obrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"S\'ha reconegut la cara. Prem per obrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"S\'ha reconegut la cara. Prem la icona per obrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mou cap a l\'esquerra"</item>
<item msgid="5558598599408514296">"Mou cap avall"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continua"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mode de convidat"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Estàs en mode de convidat"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"En afegir un usuari nou, se sortirà del mode de convidat i se suprimiran totes les aplicacions i dades de la sessió de convidat actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"S\'ha assolit el límit d\'usuaris"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Pots afegir fins a <xliff:g id="COUNT">%d</xliff:g> usuaris.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Captures de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Missatges generals"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplicacions instantànies"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuració"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Emmagatzematge"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Suggeriments"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicacions instantànies"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"càmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicació"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micròfon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravació de pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per emetre aquesta sessió, obre l\'aplicació."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicació desconeguda"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Atura l\'emissió"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositius disponibles per a la sortida d\'àudio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emet"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les persones properes amb dispositius Bluetooth compatibles poden escoltar el contingut multimèdia que emets"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fet"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S\'ha copiat"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignora el text copiat"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora la IU de còpia"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edita el text que has copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edita la imatge que has copiat"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envia a un dispositiu proper"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}other{# notificacions}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"S\'està emetent"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emet <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Canvia la sortida"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconeguda"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index 2d13e568d5f3..242cbd3f2030 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -88,7 +88,7 @@
</string-array>
<string-array name="tile_states_color_correction">
<item msgid="2840507878437297682">"No disponible"</item>
- <item msgid="1909756493418256167">"Desactivat"</item>
+ <item msgid="1909756493418256167">"Desactivada"</item>
<item msgid="4531508423703413340">"Activada"</item>
</string-array>
<string-array name="tile_states_inversion">
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"Desactivat"</item>
+ <item msgid="5966994759929723339">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 438b2bc33e48..538eaac1469e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrzeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ověření dokončíte klepnutím na Potvrdit"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Odemknuto obličejem. Klepněte na ikonu odemknutí."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odemknuto obličejem. Pokračujte stisknutím."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obličej rozpoznán. Pokračujte stisknutím."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ověřeno"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použít kód PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použít gesto"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otočení obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Spořič obrazovky"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Přístup k fotoaparátu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Přístup k mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupné"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Otevřete přejetím prstem nahoru"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Otevřete klepnutím na ikonu odemknutí"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Odemknuto obličejem. Klepněte na ikonu odemknutí."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odemknuto obličejem. Stisknutím otevřete."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Obličej rozpoznán. Stisknutím otevřete."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Přesunout doleva"</item>
<item msgid="5558598599408514296">"Přesunout dolů"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ano, pokračovat"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Režim hosta"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Jste v režimu hosta"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Přidáním nového uživatele ukončíte režim hosta a smažete všechny aplikace a data z aktuální relace hosta."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Bylo dosaženo limitu uživatelů"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="few">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatele.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozornění"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snímky obrazovek"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Všeobecné zprávy"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Okamžité aplikace"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavit"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Úložiště"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string>
<string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikace"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"nahrávání obrazovky"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pokud chcete odesílat relaci, otevřete aplikaci."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznámá aplikace"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastavit odesílání"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupná zařízení pro zvukový výstup."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysílání"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lidé ve vašem okolí s kompatibilními zařízeními Bluetooth mohou poslouchat média, která vysíláte"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikace <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odmítnout zkopírovaný text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zavřít uživatelské rozhraní kopírování"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upravit zkopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upravit zkopírovaný obrázek"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odeslat do zařízení v okolí"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparát a mikrofon jsou vypnuté"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysílání"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Změna výstupu"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznámé"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 2af84d97653c..64e83e0c31b8 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Vypnuto"</item>
<item msgid="460891964396502657">"Zapnuto"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupné"</item>
+ <item msgid="8014986104355098744">"Vypnuto"</item>
+ <item msgid="5966994759929723339">"Zapnuto"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bebd5c6d4575..44b0d4bcc4c1 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekræftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tryk på Bekræft for at udføre"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Låst op vha. ansigt. Tryk på oplåsningsikonet for at fortsætte."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst op ved hjælp af ansigt. Tryk for at fortsætte."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansigt genkendt. Tryk for at fortsætte."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansigt genkendt. Tryk på oplåsningsikonet for at fortsætte."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Godkendt"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Brug pinkode"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Brug mønster"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Pauseskærm"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraadgang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonadgang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgængelig"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Stryg opad for at åbne"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Tryk på oplåsningsikonet for at åbne"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Låst op vha. ansigt. Tryk på oplåsningsikonet for at åbne."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Låst op ved hjælp af ansigt. Tryk for at åbne."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansigt genkendt. Tryk for at åbne."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansigt genkendt. Tryk på oplåsningsikonet for at åbne."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Flyt til venstre"</item>
<item msgid="5558598599408514296">"Flyt ned"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsæt"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gæstetilstand"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Gæstetilstand er aktiveret"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Hvis du tilføjer en ny bruger, deaktiveres gæstetilstanden, og alle apps og data slettes fra den aktuelle gæstesession."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Grænsen for antal brugere er nået"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Du kan tilføje op til <xliff:g id="COUNT">%d</xliff:g> bruger.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Underretninger"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Generelle meddelelser"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfiguration"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagerplads"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokation"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"skærmoptagelse"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Åbn appen for at caste denne session."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukendt app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop med at caste"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheder, der er tilgængelige for lydoutput."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Sådan fungerer udsendelser"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Udsendelse"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i nærheden, som har kompatible Bluetooth-enheder, kan lytte til det medie, du udsender"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Udfør"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopieret"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Afvis kopieret tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Luk brugerfladen for kopi"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger kopieret tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger kopieret billede"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til enhed i nærheden"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er slået fra"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikation}one{# notifikation}other{# notifikationer}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Udsender"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Udsend <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skift output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukendt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 0fe06b3433c3..f0132dc66130 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Fra"</item>
<item msgid="460891964396502657">"Til"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ikke tilgængelig"</item>
+ <item msgid="8014986104355098744">"Fra"</item>
+ <item msgid="5966994759929723339">"Til"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 85f8671b9ad3..8a1520189055 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bestätigt"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Zum Abschließen auf \"Bestätigen\" tippen"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Gerät mit dem Gesicht entsperrt. Tippe auf das Symbol „Entsperren“, um fortzufahren."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Gerät mit dem Gesicht entsperrt. Tippe, um fortzufahren."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesicht erkannt. Tippe, um fortzufahren."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesicht erkannt. Tippe zum Fortfahren auf das Symbol „Entsperren“."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifiziert"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN verwenden"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Muster verwenden"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Bildschirmschoner"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamerazugriff"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonzugriff"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Verfügbar"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Zum Öffnen nach oben wischen"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Tippe zum Öffnen auf das Symbol „Entsperren“"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Gerät mit dem Gesicht entsperrt. Tippe zum Öffnen auf das Symbol „Entsperren“."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Gerät mit dem Gesicht entsperrt. Tippe zum Öffnen."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gesicht erkannt. Tippe zum Öffnen."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gesicht erkannt. Tippe zum Öffnen auf das Symbol „Entsperren“."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Nach links bewegen"</item>
<item msgid="5558598599408514296">"Nach unten bewegen"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, weiter"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gastmodus"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Du befindest dich im Gastmodus"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Durch Hinzufügen eines neuen Nutzers wird der Gastmodus beendet und alle Apps und Daten der aktuellen Gastsitzung werden gelöscht."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Nutzerlimit erreicht"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Du kannst bis zu <xliff:g id="COUNT">%d</xliff:g> Nutzer hinzufügen.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Benachrichtigungen"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Nachrichten"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Android Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Einrichtung"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Speicher"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hinweise"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"Kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"Standort"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"Mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"Bildschirmaufzeichnung"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öffne zum Streamen dieser Sitzung die App."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unbekannte App"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Streaming beenden"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Für die Audioausgabe verfügbare Geräte."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Nachricht an alle"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personen, die in der Nähe sind und kompatible Bluetooth-Geräten haben, können sich die Medien anhören, die du per Nachricht an alle sendest"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fertig"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Von <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopierten Text verwerfen"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopieren-Benutzeroberfläche schließen"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopierten Text bearbeiten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopiertes Bild bearbeiten"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"An Gerät in der Nähe senden"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera und Mikrofon ausgeschaltet"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Übertragung läuft"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ausgabe ändern"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unbekannt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index ba610b33ccfa..bc50e1603ea4 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Aus"</item>
<item msgid="460891964396502657">"An"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nicht verfügbar"</item>
+ <item msgid="8014986104355098744">"Aus"</item>
+ <item msgid="5966994759929723339">"An"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 35748343a225..5787a4437f24 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Επιβεβαιώθηκε"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Πατήστε Επιβεβαίωση για ολοκλήρωση"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Ξεκλ. με αναγν. προσώπου. Πατ. το εικον. ξεκλ. για συνέχεια."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για συνέχεια."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για συνέχεια."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Το πρόσωπο αναγνωρ. Πατήστε το εικον. ξεκλειδ. για συνέχεια."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ολοκληρώθηκε ο έλεγχος ταυτότητας"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Χρήση PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Χρήση μοτίβου"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Προφύλαξη οθόνης"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Πρόσβαση κάμερας"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Πρόσβαση μικροφώνου"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Διαθέσιμη"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Σύρετε προς τα επάνω για άνοιγμα"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Πατήστε το εικονίδιο ξεκλειδώματος για άνοιγμα"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Ξεκλ. με αναγν. προσώπου. Πατ. το εικον. ξεκλ. για άνοιγμα."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για άνοιγμα."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για άνοιγμα."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Το πρόσωπο αναγνωρ. Πατήστ. το εικον. ξεκλειδ. για άνοιγμα."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Μετακίνηση αριστερά"</item>
<item msgid="5558598599408514296">"Μετακίνηση κάτω"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ναι, συνέχεια"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Λειτουργία επισκέπτη"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Βρίσκεστε σε λειτουργία επισκέπτη"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Με την προσθήκη νέου χρήστη θα γίνει έξοδος από τη λειτουργία επισκέπτη και θα διαγραφούν όλες οι εφαρμογές και τα δεδομένα από την τρέχουσα περίοδο σύνδεσης επισκέπτη."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Συμπληρώθηκε το όριο χρηστών"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Μπορείτε να προσθέσετε έως <xliff:g id="COUNT">%d</xliff:g> χρήστες.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ειδοποιήσεις"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Μπαταρία"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Στιγμιότυπα οθόνης"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Γενικά μηνύματα"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Εφαρμογές"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Ρύθμιση"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Αποθηκευτικός χώρος"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Συμβουλές"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Εφαρμογές"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"κάμερα"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"τοποθεσία"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"μικρόφωνο"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"εγγραφή οθόνης"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Για μετάδοση της περιόδου σύνδεσης, ανοίξτε την εφαρμογή."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Άγνωστη εφαρμογή"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Διακοπή μετάδοσης"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Διαθέσιμες συσκευές για έξοδο ήχου."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Πώς λειτουργεί η μετάδοση"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Μετάδοση"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Οι άνθρωποι με συμβατές συσκευές Bluetooth που βρίσκονται κοντά σας μπορούν να ακούσουν το μέσο που μεταδίδετε."</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Τέλος"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Αντιγράφηκε"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Από <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Παράβλεψη αντιγραμμένου κειμένου"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Παράβλεψη διεπαφής χρήστη αντιγραφής"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Επεξεργασία αντιγραμμένου κειμένου"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Επεξεργασία αντιγραμμένης εικόνας"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Αποστολή σε κοντινή συσκευή"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Το ξυπνητήρι ρυθμίστηκε"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Η κάμερα και το μικρόφωνο έχουν απενεργοποιηθεί"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ειδοποίηση}other{# ειδοποιήσεις}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Μετάδοση"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Διακοπή μετάδοσης με την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Εάν κάνετε μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g> ή αλλάξετε την έξοδο, η τρέχουσα μετάδοση θα σταματήσει"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Αλλαγή εξόδου"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Άγνωστο"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 74c091e4ed18..352af39bfe11 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Ανενεργή"</item>
<item msgid="460891964396502657">"Ενεργή"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Μη διαθέσιμο"</item>
+ <item msgid="8014986104355098744">"Ανενεργό"</item>
+ <item msgid="5966994759929723339">"Ενεργό"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 6f339b56a292..8b2be142ff14 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Unlocked by face. Press the unlock icon to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Press the unlock icon to open"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Unlocked by face. Press the unlock icon to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Move left"</item>
<item msgid="5558598599408514296">"Move down"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Guest mode"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"You are in guest mode"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Adding a new user will exit guest mode and delete all apps and data from the current guest session."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index 6f8cfb695ac6..56cdbef092f2 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 9c88ac21ee82..023c7981bea0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Unlocked by face. Press the unlock icon to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Press the unlock icon to open"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Unlocked by face. Press the unlock icon to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Move left"</item>
<item msgid="5558598599408514296">"Move down"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Guest mode"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"You are in guest mode"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Adding a new user will exit guest mode and delete all apps and data from the current guest session."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index 6f8cfb695ac6..56cdbef092f2 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6f339b56a292..8b2be142ff14 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Unlocked by face. Press the unlock icon to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Press the unlock icon to open"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Unlocked by face. Press the unlock icon to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Move left"</item>
<item msgid="5558598599408514296">"Move down"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Guest mode"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"You are in guest mode"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Adding a new user will exit guest mode and delete all apps and data from the current guest session."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index 6f8cfb695ac6..56cdbef092f2 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 6f339b56a292..8b2be142ff14 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Unlocked by face. Press the unlock icon to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Press the unlock icon to open"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Unlocked by face. Press the unlock icon to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Unlocked by face. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Face recognised. Press to open."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Face recognised. Press the unlock icon to open."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Move left"</item>
<item msgid="5558598599408514296">"Move down"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Guest mode"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"You are in guest mode"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Adding a new user will exit guest mode and delete all apps and data from the current guest session."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerts"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"General Messages"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index 6f8cfb695ac6..56cdbef092f2 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Unavailable"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 06485200c04d..76361174739a 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎Confirmed‎‏‎‎‏‎"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎Tap Confirm to complete‎‏‎‎‏‎"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎Unlocked by face. Press the unlock icon to continue.‎‏‎‎‏‎"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎Unlocked by face. Press to continue.‎‏‎‎‏‎"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎Face recognized. Press to continue.‎‏‎‎‏‎"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎Face recognized. Press the unlock icon to continue.‎‏‎‎‏‎"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎Authenticated‎‏‎‎‏‎"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎Use PIN‎‏‎‎‏‎"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎Use pattern‎‏‎‎‏‎"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‎Auto-rotate‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎Auto-rotate screen‎‏‎‎‏‎"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎Location‎‏‎‎‏‎"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎Screen saver‎‏‎‎‏‎"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎Camera access‎‏‎‎‏‎"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎Mic access‎‏‎‎‏‎"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‎Available‎‏‎‎‏‎"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎Swipe up to open‎‏‎‎‏‎"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎Press the unlock icon to open‎‏‎‎‏‎"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎Unlocked by face. Press the unlock icon to open.‎‏‎‎‏‎"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎Unlocked by face. Press to open.‎‏‎‎‏‎"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎Face recognized. Press to open.‎‏‎‎‏‎"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎Face recognized. Press the unlock icon to open.‎‏‎‎‏‎"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎Move left‎‏‎‎‏‎"</item>
<item msgid="5558598599408514296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎Move down‎‏‎‎‏‎"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎Do you want to continue your session?‎‏‎‎‏‎"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎Start over‎‏‎‎‏‎"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎Yes, continue‎‏‎‎‏‎"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎Guest mode‎‏‎‎‏‎"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎You are in guest mode‎‏‎‎‏‎"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Adding a new user will exit guest mode and delete all apps and data from the current guest session.‎‏‎‎‏‎"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎User limit reached‎‏‎‎‏‎"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‎You can add up to ‎‏‎‎‏‏‎<xliff:g id="COUNT">%d</xliff:g>‎‏‎‎‏‏‏‎ users.‎‏‎‎‏‎</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎Alerts‎‏‎‎‏‎"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎Battery‎‏‎‎‏‎"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎Screenshots‎‏‎‎‏‎"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎General Messages‎‏‎‎‏‎"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎Instant Apps‎‏‎‎‏‎"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎Setup‎‏‎‎‏‎"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎Storage‎‏‎‎‏‎"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‎Hints‎‏‎‎‏‎"</string>
<string name="instant_apps" msgid="8337185853050247304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎Instant Apps‎‏‎‎‏‎"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎camera‎‏‎‎‏‎"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎location‎‏‎‎‏‎"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎microphone‎‏‎‎‏‎"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎screen recording‎‏‎‎‏‎"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎No title‎‏‎‎‏‎"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Standby‎‏‎‎‏‎"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎Magnification Window‎‏‎‎‏‎"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎To cast this session, please open the app.‎‏‎‎‏‎"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎Unknown app‎‏‎‎‏‎"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎Stop casting‎‏‎‎‏‎"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎Available devices for audio output.‎‏‎‎‏‎"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎How broadcasting works‎‏‎‎‏‎"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎Broadcast‎‏‎‎‏‎"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting‎‏‎‎‏‎"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎Done‎‏‎‎‏‎"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎Copied‎‏‎‎‏‎"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎From ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎Dismiss copied text‎‏‎‎‏‎"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎Dismiss copy UI‎‏‎‎‏‎"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎Edit copied text‎‏‎‎‏‎"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎Edit copied image‎‏‎‎‏‎"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎Send to nearby device‎‏‎‎‏‎"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎Alarm set‎‏‎‎‏‎"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎Camera and mic are off‎‏‎‎‏‎"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notification‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notifications‎‏‎‎‏‎}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎Broadcasting‎‏‎‎‏‎"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎Stop broadcasting ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎If you broadcast ‎‏‎‎‏‏‎<xliff:g id="SWITCHAPP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ or change the output, your current broadcast will stop‎‏‎‎‏‎"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎Broadcast ‎‏‎‎‏‏‎<xliff:g id="SWITCHAPP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎Change output‎‏‎‎‏‎"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎Unknown‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index 99ef50c9d8af..3a8e34c2ebdc 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎Off‎‏‎‎‏‎"</item>
<item msgid="460891964396502657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎On‎‏‎‎‏‎"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎Unavailable‎‏‎‎‏‎"</item>
+ <item msgid="8014986104355098744">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎Off‎‏‎‎‏‎"</item>
+ <item msgid="5966994759929723339">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎On‎‏‎‎‏‎"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 7ff395a9ef8d..babf483d9359 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Desbloqueo con rostro. Presiona ícono desbl. para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueo con rostro. Presiona para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rostro reconocido. Presiona para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rostro reconocido. Presiona el desbloqueo para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protector de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al mic."</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Presiona el ícono de desbloquear para abrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Desbloqueo con rostro. Presiona ícono desbloq. para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueo con rostro. Presiona para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rostro reconocido. Presiona para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rostro reconocido. Presiona el desbloqueo para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mover hacia la izquierda"</item>
<item msgid="5558598599408514296">"Mover hacia abajo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo de Invitado"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en el modo de invitado"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si agregas un usuario nuevo, se desactivará el modo de invitado y se borrarán todas las apps y los datos de la sesión de invitado actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzaste el límite de usuarios"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Puedes agregar hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensajes generales"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Apps instantáneas"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuración"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apps instantáneas"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"Grabación de pant."</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sesión, abre la app"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconocida"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Detener transmisión"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para salida de audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que transmites"</string>
@@ -898,7 +904,7 @@
<string name="person_available" msgid="2318599327472755472">"Disponible"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No establecida"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No se estableció alarma"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas dactilares"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Listo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Se copió"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Descartar el texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Descartar la copia de la IU"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar el texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar la imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivos cercanos"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia la salida"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconocido"</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 6b572e4920c6..2dca6109d5d1 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Sí"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"No"</item>
+ <item msgid="5966994759929723339">"Sí"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4d0869edcd63..7cccc9693cf9 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar la acción"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Desbloqueado con datos faciales. Pulsa el icono desbloquear para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado con la cara. Pulsa para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Cara reconocida. Pulsa para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Cara reconocida. Pulsa el icono de desbloquear para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Se ha autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Salvapantallas"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pulsa el icono desbloquear para abrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Desbloqueado con datos faciales. Pulsa el icono desbloquear para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado con la cara. Pulsa para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Cara reconocida. Pulsa para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Cara reconocida. Pulsa el icono de desbloquear para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mover hacia la izquierda"</item>
<item msgid="5558598599408514296">"Mover hacia abajo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con tu sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo Invitado"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en modo Invitado"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si añades un nuevo usuario, saldrás del modo Invitado y se eliminarán todas las aplicaciones y datos de la sesión de invitado actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Has alcanzado el límite de usuarios"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Puedes añadir hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensajes generales"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplicaciones Instantáneas"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuración"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicaciones Instantáneas"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"grabación de pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para enviar esta sesión, abre la aplicación."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación desconocida"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dejar de enviar contenido"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para la salida de audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que emites"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hecho"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Descartar texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Cerrar la interfaz de copia"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo cercano"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar salida"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconocido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index e4310af3d531..e1082bf4e48c 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -63,8 +63,8 @@
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"No disponible"</item>
- <item msgid="5776427577477729185">"Desactivada"</item>
- <item msgid="7105052717007227415">"Activada"</item>
+ <item msgid="5776427577477729185">"Desactivado"</item>
+ <item msgid="7105052717007227415">"Activado"</item>
</string-array>
<string-array name="tile_states_bt">
<item msgid="5330252067413512277">"No disponible"</item>
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"No disponible"</item>
+ <item msgid="8014986104355098744">"Desactivado"</item>
+ <item msgid="5966994759929723339">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2bb5757b76e6..522599e1f6a7 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kinnitatud"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lõpuleviimiseks puudutage nuppu Kinnita"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Avati näoga. Jätkamiseks vajutage avamise ikooni."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avati näoga. Vajutage jätkamiseks."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nägu tuvastati. Vajutage jätkamiseks."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nägu tuvastati. Jätkamiseks vajutage avamise ikooni."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenditud"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Kasuta PIN-koodi"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Kasuta mustrit"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekraanisäästja"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Juurdepääs kaamerale"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Juurdepääs mikrofonile"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Saadaval"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Pühkige avamiseks üles"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Avamiseks vajutage avamise ikooni"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Avati näoga. Avamiseks vajutage avamise ikooni."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Avati näoga. Avamiseks vajutage."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Nägu tuvastati. Avamiseks vajutage."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Nägu tuvastati. Avamiseks vajutage avamise ikooni."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Teisalda vasakule"</item>
<item msgid="5558598599408514296">"Teisalda alla"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jah, jätka"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Külalisrežiim"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Olete külalisrežiimis"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Uue kasutaja lisamisel suletakse külalisrežiim ning praeguse külastajaseansi rakendused ja andmed kustutatakse."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Kasutajate limiit on täis"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Võite lisada kuni <xliff:g id="COUNT">%d</xliff:g> kasutajat.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Hoiatused"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Aku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekraanipildid"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Üldised sõnumid"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Installimata avatavad rakendused"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Seadistamine"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Salvestusruum"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vihjed"</string>
<string name="instant_apps" msgid="8337185853050247304">"Installimata avatavad rakendused"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kaamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"asukoht"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekraanikuva salvest."</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Selle seansi ülekandmiseks avage rakendus."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tundmatu rakendus"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lõpeta ülekanne"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Saadaolevad seadmed heli esitamiseks."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Ülekanne"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Teie läheduses olevad inimesed, kellel on ühilduvad Bluetooth-seadmed, saavad kuulata teie ülekantavat meediat"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopeeritud"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Rakendusest <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Loobu kopeeritud tekstist"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Koopiast loobumise kasutajaliides"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muuda kopeeritud teksti"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muuda kopeeritud pilti"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Saada läheduses olevasse seadmesse"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kaamera ja mikrofon on välja lülitatud"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Edastamine"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Rakenduse <xliff:g id="SWITCHAPP">%1$s</xliff:g> ülekandmine"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Väljundi muutmine"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tundmatu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 29895d1a437a..07eddef9383e 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Väljas"</item>
<item msgid="460891964396502657">"Sees"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Pole saadaval"</item>
+ <item msgid="8014986104355098744">"Väljas"</item>
+ <item msgid="5966994759929723339">"Sees"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index e6948e8dfd3d..64661051feab 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Berretsita"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Amaitzeko, sakatu \"Berretsi\""</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Aurpegiaren bidez desblokeatu da. Aurrera egiteko, sakatu desblokeatzeko ikonoa."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ezagutu da aurpegia. Sakatu aurrera egiteko."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ezagutu da aurpegia. Aurrera egiteko, sakatu desblokeatzeko ikonoa."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikatuta"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Erabili PINa"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Erabili eredua"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Pantaila-babeslea"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonoa"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Baimenduta"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Irekitzeko, sakatu desblokeatzeko ikonoa"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Aurpegiaren bidez desblokeatu da. Irekitzeko, sakatu desblokeatzeko ikonoa."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Aurpegiaren bidez desblokeatu da. Sakatu irekitzeko."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ezagutu da aurpegia. Sakatu irekitzeko."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ezagutu da aurpegia. Irekitzeko, sakatu desblokeatzeko ikonoa."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Eraman ezkerrera"</item>
<item msgid="5558598599408514296">"Eraman behera"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bai, jarraitu"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gonbidatu modua"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Gonbidatu moduan zaude"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Beste erabiltzaile bat gehituz gero, gonbidatu modua itxiko da eta oraingo gonbidatuentzako saioko aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Erabiltzaile-mugara iritsi zara"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Gehienez, <xliff:g id="COUNT">%d</xliff:g> erabiltzaile gehi ditzakezu.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertak"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Pantaila-argazkiak"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mezu orokorrak"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Zuzeneko aplikazioak"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurazioa"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Memoria"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Aholkuak"</string>
<string name="instant_apps" msgid="8337185853050247304">"Zuzeneko aplikazioak"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"kokapena"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonoa"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"pantaila-grabaketa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Saioa ireki nahi baduzu, ireki aplikazioa."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikazio ezezaguna"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Gelditu igorpena"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio-irteerarako gailu erabilgarriak."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Iragarri"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth bidezko gailu bateragarriak dituzten inguruko pertsonek iragartzen ari zaren multimedia-edukia entzun dezakete"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Eginda"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiatu da"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Jatorria: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Baztertu kopiatutako testua"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopiatutako UIa baztertzeko botoia"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editatu kopiatutako testua"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editatu kopiatutako irudia"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Bidali inguruko gailu batera"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera eta mikrofonoa desaktibatuta daude"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Igortzen"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Igorri <xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Aldatu audio-irteera"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ezezaguna"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index baddea16b833..3bf49c8e0c77 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desaktibatuta"</item>
<item msgid="460891964396502657">"Aktibatuta"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ez dago erabilgarri"</item>
+ <item msgid="8014986104355098744">"Desaktibatuta"</item>
+ <item msgid="5966994759929723339">"Aktibatuta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ae86255f56ef..726e3abec4bd 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تأیید شد"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"برای تکمیل، روی تأیید ضربه بزنید"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"قفلْ با چهره باز شد. برای ادامه، نماد قفل‌گشایی را فشار دهید."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"قفلْ با چهره باز شد. برای ادامه، فشار دهید."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چهره شناسایی شد. برای ادامه، فشار دهید."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چهره شناسایی شد. برای ادامه، نماد قفل‌گشایی را فشار دهید."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"راستی‌آزمایی‌شده"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استفاده از پین"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استفاده از الگو"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحه‌نمایش"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"محافظ صفحه"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"دسترسی به دوربین"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"دسترسی به میکروفون"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"دردسترس"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"برای باز کردن، انگشتتان را تند به‌بالا بکشید"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"برای باز کردن، نماد قفل‌گشایی را فشار دهید"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"قفلْ با چهره باز شد. برای باز کردن، نماد قفل‌گشایی را فشار دهید."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"قفلْ با چهره باز شد. برای باز کردن، فشار دهید."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"چهره شناسایی شد. برای باز کردن، فشار دهید."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"چهره شناسایی شد. برای باز کردن، نماد قفل‌گشایی را فشار دهید."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"انتقال به‌چپ"</item>
<item msgid="5558598599408514296">"انتقال به‌پایین"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"بله، ادامه داده شود"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"حالت مهمان"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"در حالت مهمان هستید"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"با افزودن کاربر جدید، از حالت مهمان خارج خواهید شد و همه برنامه‌ها و داده‌ها از جلسه مهمان کنونی حذف خواهند شد."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"به تعداد مجاز تعداد کاربر رسیده‌اید"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">می‌توانید حداکثر <xliff:g id="COUNT">%d</xliff:g> کاربر اضافه کنید.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"هشدارها"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"باتری"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"نماگرفت‌ها"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"پیام‌های عمومی"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"برنامه‌های فوری"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"راه‌اندازی"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"فضای ذخیره‌سازی"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"نکات"</string>
<string name="instant_apps" msgid="8337185853050247304">"برنامه‌های فوری"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"دوربین"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مکان"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"میکروفون"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ضبط صفحه‌نمایش"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگ‌نمایی"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"برای ارسال محتوای این جلسه، لطفاً برنامه را باز کنید."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"برنامه ناشناس"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف ارسال محتوا"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"دستگاه‌های دردسترس برای خروجی صدا."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همه‌فرتستی چطور کار می‌کند"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"همه‌فرستی"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏افرادی که در اطرافتان دستگاه‌های Bluetooth سازگار دارند می‌توانند به رسانه‌ای که همه‌فرستی می‌کنید گوش کنند"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"تمام"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"رد شدن نوشتار کپی‌شده"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"رد کردن رابط کاربری کپی کردن"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ویرایش نوشتار کپی‌شده"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ویرایش تصویر کپی‌شده"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ارسال به دستگاهی در اطراف"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"دوربین و میکروفون خاموش هستند"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"همه‌فرستی"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"همه‌فرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همه‌فرستی کنید یا خروجی را تغییر دهید، همه‌فرستی کنونی متوقف خواهد شد"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"همه‌فرستی <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغییر خروجی"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"نامشخص"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index ecc8d1cc7b13..85f0bfdf86dd 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"خاموش"</item>
<item msgid="460891964396502657">"روشن"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"دردسترس نیست"</item>
+ <item msgid="8014986104355098744">"خاموش"</item>
+ <item msgid="5966994759929723339">"روشن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6a023337acf4..bbcecfed001d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Vahvistettu"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Valitse lopuksi Vahvista"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Avattu kasvojen avulla. Jatka lukituksen avauskuvakkeella."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avattu kasvojen avulla. Jatka painamalla."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Kasvot tunnistettu. Jatka painamalla."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Todennettu"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Käytä PIN-koodia"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Käytä kuviota"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Näytönsäästäjä"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pääsy kameraan"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pääsy mikrofoniin"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Käytettävissä"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Avaa pyyhkäisemällä ylös"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Jatka painamalla lukituksen avauskuvaketta."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Avattu kasvojen avulla. Jatka lukituksen avauskuvakkeella."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Avattu kasvojen avulla. Avaa painamalla."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Kasvot tunnistettu. Avaa painamalla."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Siirrä vasemmalle"</item>
<item msgid="5558598599408514296">"Siirrä alas"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Kyllä, haluan jatkaa"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Vierastila"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Olet vierastilassa"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Uuden käyttäjän lisääminen poistaa sinut vierastilasta. Kaikki sovellukset ja data poistetaan myös samalla nykyisestä vierailija-käyttökerrasta."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Käyttäjäraja saavutettu"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Voit lisätä korkeintaan <xliff:g id="COUNT">%d</xliff:g> käyttäjää.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ilmoitukset"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akku"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Kuvakaappaukset"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Yleiset viestit"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Määritys"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Tallennustila"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vihjeet"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"sijainti"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoni"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"näytön tallennus"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jos haluat striimata tämän käyttökerran, avaa sovellus."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tuntematon sovellus"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lopeta striimaus"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Käytettävissä olevat audiolaitteet"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Lähetys"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lähistöllä olevat ihmiset, joilla on yhteensopiva Bluetooth-laite, voivat kuunnella lähettämääsi mediaa"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopioitu"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Lähde: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hylkää kopioitu teksti"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hylkää kopioitu UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muokkaa kopioitua tekstiä"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muokkaa kopioitua kuvaa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Lähetä lähellä olevaan laitteeseen"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ja mikrofoni ovat pois päältä"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Lähettää"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lähetä <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Muuta ulostuloa"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tuntematon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index 5844fb9b79c5..1505dc5c06bb 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Poissa päältä"</item>
<item msgid="460891964396502657">"Päällä"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ei saatavilla"</item>
+ <item msgid="8014986104355098744">"Poissa päältä"</item>
+ <item msgid="5966994759929723339">"Päällä"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 0d67eda0756b..ee1790a47771 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Touchez Confirmer pour terminer"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Déverrouillé avec le visage. Appuyez Déverrouiller pour cont."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverrouillé avec le visage. Appuyez pour continuer."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur Déverrouiller pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un NIP"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Écran de veille"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Accessible"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Appuyez sur l\'icône Déverrouiller pour ouvrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Déverrouillé avec le visage. Appuyez Déverrouiller pour ouvrir"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Déverrouillé avec le visage. Appuyez pour ouvrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Visage reconnu. Appuyez pour ouvrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Visage reconnu. Appuyez sur Déverrouiller pour ouvrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Déplacer vers la gauche"</item>
<item msgid="5558598599408514296">"Déplacer vers le bas"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mode Invité"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un nouvel utilisateur, vous quitterez le mode Invité, et toutes les applications et données de la session d\'invité en cours seront supprimées."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateur.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pile"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Saisies d\'écran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Messages généraux"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Applications instantanées"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuration"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Conseils"</string>
<string name="instant_apps" msgid="8337185853050247304">"Applications instantanées"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement d\'écran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour diffuser cette session, veuillez ouvrir l\'application."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Application inconnue"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Diffusion"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité disposant d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"À partir de <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorer le texte copié"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorer la copie de l\'IU"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Changer la sortie"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Inconnue"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index 9d78e91f0f69..4ec00846283a 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non accessible"</item>
+ <item msgid="8014986104355098744">"Désactivé"</item>
+ <item msgid="5966994759929723339">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 23f3e7c584dd..70451e3a9785 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Appuyez sur \"Confirmer\" pour terminer"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Déverrouillé par visage. Appuyez sur icône déverrouillage pour continuer."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverrouillé par visage. Appuyez pour continuer."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un code PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Économiseur d\'écran"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au micro"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
@@ -313,12 +317,13 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayer vers le haut pour ouvrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Appuyez sur l\'icône de déverrouillage pour ouvrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Déverrouillé par visage. Appuyez sur icône déverrouillage pour ouvrir."</string>
- <string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Déplacer vers la gauche"</item>
- <item msgid="5558598599408514296">"Déplacer vers le bas"</item>
- <item msgid="4844142668312841831">"Déplacer vers la droite"</item>
- <item msgid="5640521437931460125">"Déplacer vers le haut"</item>
- </string-array>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Déverrouillé par visage. Appuyez pour ouvrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Visage reconnu. Appuyez pour ouvrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour ouvrir."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser la NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -345,6 +350,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mode Invité"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un utilisateur, le mode Invité sera désactivé et toutes les applis et les données de la session Invité actuelle seront supprimées."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite nombre utilisateurs atteinte"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Vous pouvez ajouter <xliff:g id="COUNT">%d</xliff:g> profil utilisateur.</item>
@@ -691,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Captures d\'écran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Nouveaux messages"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Espace de stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Astuces"</string>
<string name="instant_apps" msgid="8337185853050247304">"Applis instantanées"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"l\'appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"la position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"le micro"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement écran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour caster cette session, veuillez ouvrir l\'appli."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Appli inconnue"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annonce"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité équipées d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorer le texte copié"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Désactiver l\'interface de copie"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Modifier le résultat"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Inconnue"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index 47fa9c571402..8c6c4f555a5c 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponible"</item>
+ <item msgid="8014986104355098744">"Désactivé"</item>
+ <item msgid="5966994759929723339">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 5f89f8c362fd..979a560d7b5d 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar o proceso"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Usouse o desbloqueo facial. Preme a icona de desbloquear."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Usouse o desbloqueo facial. Preme para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Recoñeceuse a cara. Preme para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Recoñeceuse a cara. Preme a icona de desbloquear."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrón"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protector de pantalla"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso á cámara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso ao micrófono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dispoñible"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasa o dedo cara arriba para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Preme a icona de desbloquear para abrir a porta"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Usouse o desbloqueo facial. Preme a icona de desbloquear."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Usouse o desbloqueo facial. Preme para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Recoñeceuse a cara. Preme para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Recoñeceuse a cara. Preme a icona de desbloquear para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mover cara á esquerda"</item>
<item msgid="5558598599408514296">"Mover cara abaixo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Si, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo de convidado"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás usando o modo de convidado"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao engadir un usuario novo, sairás do modo de convidado e eliminaranse todas as aplicacións e datos da sesión de convidado actual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzouse o límite de usuarios"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Podes engadir ata <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batería"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de pantalla"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensaxes xerais"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplicacións Instantáneas"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Consellos"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicacións Instantáneas"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"a cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"a localiz."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"o micrófono"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravación pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para emitir esta sesión, abre a aplicación."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación descoñecida"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Deter emisión"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos dispoñibles para a saída de audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Difusión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As persoas que estean preto de ti e que dispoñan de dispositivos Bluetooth compatibles poden escoitar o contido multimedia que difundas"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Feito"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiouse"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorar texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar interface de copia"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imaxe copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo próximo"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A cámara e o micrófono están desactivados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Difusión"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar de saída"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Descoñecida"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index 229836c76e09..590ec4ac515c 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non dispoñible"</item>
+ <item msgid="8014986104355098744">"Desactivado"</item>
+ <item msgid="5966994759929723339">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5648a4568d1e..02e5807ff0b6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"પુષ્ટિ કરી"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"પરીક્ષણ પૂર્ણ કરવા કન્ફર્મ કરોને ટૅપ કરો"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ચહેરા દ્વારા અનલૉક કર્યું. આગળ વધવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ચહેરા દ્વારા અનલૉક કર્યું. આગળ વધવા માટે દબાવો."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ચહેરો ઓળખ્યો. આગળ વધવા માટે દબાવો."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ચહેરો ઓળખ્યો. આગળ વધવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"પ્રમાણિત"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"પિનનો ઉપયોગ કરો"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"પૅટર્નનો ઉપયોગ કરો"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ઑટો રોટેટ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ઑટો રોટેટ સ્ક્રીન"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"સ્થાન"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"સ્ક્રીન સેવર"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"કૅમેરાનો ઍક્સેસ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"માઇકનો ઍક્સેસ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ઉપલબ્ધ છે"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ખોલવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ખોલવા માટે \'અનલૉક કરો\' આઇકન દબાવો"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ચહેરા દ્વારા અનલૉક કર્યું. ખોલવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ચહેરા દ્વારા અનલૉક કર્યું. ખોલવા માટે દબાવો."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ચહેરો ઓળખ્યો. ખોલવા માટે દબાવો."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ચહેરો ઓળખ્યો. ખોલવા માટે \'અનલૉક કરો\' આઇકન દબાવો."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ડાબે ખસેડો"</item>
<item msgid="5558598599408514296">"નીચે ખસેડો"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"હા, ચાલુ રાખો"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"અતિથિ મોડ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"તમે અતિથિ મોડમાં છો"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"કોઈ નવા વપરાશકર્તાને ઉમેરવાથી અતિથિ મોડમાંથી નીકળી જવાશે તેમજ હાલના અતિથિ સત્રમાંથી તમામ ઍપ અને ડેટા ડિલીટ થઈ જશે."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"વપરાશકર્તા સંખ્યાની મર્યાદા"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">તમે <xliff:g id="COUNT">%d</xliff:g> વપરાશકર્તા સુધી ઉમેરી શકો છો.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"અલર્ટ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"બૅટરી"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"સ્ક્રીનશૉટ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"સામાન્ય સંદેશા"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"સેટઅપ કરો"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"સ્ટોરેજ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"હિન્ટ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"કૅમેરા"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"સ્થાન"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"માઇક્રોફોન"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"સ્ક્રીન રેકોર્ડિંગ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"આ સત્ર કાસ્ટ કરવા માટે, કૃપા કરીને ઍપ ખોલો."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"અજાણી ઍપ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"કાસ્ટ કરવાનું રોકો"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ઑડિયો આઉટપુટ માટે ઉપલબ્ધ ડિવાઇસ."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"બ્રોડકાસ્ટ પ્રક્રિયાની કામ કરવાની રીત"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"બ્રોડકાસ્ટ કરો"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"સુસંગત બ્લૂટૂથ ડિવાઇસ ધરાવતા નજીકના લોકો તમે જે મીડિયા બ્રોડકાસ્ટ કરી રહ્યાં છો તે સાંભળી શકે છે"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"થઈ ગયું"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"કૉપિ કરવામાં આવી"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>માંથી"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"કૉપિ કરેલી ટેક્સ્ટ છોડી દો"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"\'UI | યૂઝર ઇન્ટરફેસ (UI) કૉપિ કરો\'ને છોડી દો"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"કૉપિ કરેલી ટેક્સ્ટમાં ફેરફાર કરો"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"કૉપિ કરેલી છબીમાં ફેરફાર કરો"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"નજીકના ડિવાઇસને મોકલો"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"કૅમેરા અને માઇક બંધ છે"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# નોટિફિકેશન}one{# નોટિફિકેશન}other{# નોટિફિકેશન}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"બ્રૉડકાસ્ટ કરી રહ્યાં છે"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> બ્રોડકાસ્ટ કરવાનું રોકીએ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"જો તમે <xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો અથવા આઉટપુટ બદલો, તો તમારું હાલનું બ્રોડકાસ્ટ બંધ થઈ જશે"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"આઉટપુટ બદલો"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"અજાણ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index c502ba3e1ffa..73b372079ec9 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"બંધ છે"</item>
<item msgid="460891964396502657">"ચાલુ છે"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"અનુપલબ્ધ"</item>
+ <item msgid="8014986104355098744">"બંધ છે"</item>
+ <item msgid="5966994759929723339">"ચાલુ છે"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e16ef0f3d1be..35a6e2c74716 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि हो गई"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"\'पुष्टि करें\' पर टैप करके पूरा करें"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"चेहरे से अनलॉक किया. जारी रखने के लिए, अनलॉक आइकॉन को दबाएं."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहरे से अनलॉक किया गया. जारी रखने के लिए टैप करें."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरे की पहचान हो गई. जारी रखने के लिए टैप करें."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरे की पहचान हो गई. जारी रखने के लिए अनलॉक आइकॉन को टैप करें."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"पुष्टि हो गई"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन इस्तेमाल करें"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पैटर्न इस्तेमाल करें"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"जगह"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रीन सेवर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"कैमरे का ऐक्सेस"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक्रोफ़ोन का ऐक्सेस"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"खोलने के लिए ऊपर स्वाइप करें"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"डिवाइस अनलॉक करने के लिए, अनलॉक आइकॉन को दबाएं"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहरे से अनलॉक किया. डिवाइस अनलॉक करने के लिए, अनलॉक आइकॉन को दबाएं."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहरे से अनलॉक किया गया. डिवाइस खोलने के लिए टैप करें."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरे की पहचान हो गई. डिवाइस खोलने के लिए टैप करें."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरे की पहचान हो गई. डिवाइस खोलने के लिए अनलॉक आइकॉन को टैप करें."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"बाईं ओर ले जाएं"</item>
<item msgid="5558598599408514296">"नीचे ले जाएं"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आपको अपना सेशन जारी रखना है?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हां, जारी रखें"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"मेहमान मोड"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"आप मेहमान मोड में हैं"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"किसी नए उपयोगकर्ता को जोड़ने पर, मेहमान मोड को बंद कर दिया जाएगा. साथ ही, मेहमान के तौर पर ब्राउज़ करने के मौजूदा सेशन से, सभी ऐप्लिकेशन और डेटा को मिटा दिया जाएगा."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"अब और उपयोगकर्ता नहीं जोड़े जा सकते"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">आप ज़्यादा से ज़्यादा <xliff:g id="COUNT">%d</xliff:g> उपयोगकर्ता जोड़ सकते हैं.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सूचनाएं"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"बैटरी"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्‍क्रीनशॉट"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सामान्य संदेश"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"सेट अप"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"संकेत"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"कैमरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रीन रिकॉर्डिंग"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडियो आउटपुट के लिए उपलब्ध डिवाइस."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करें"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"आपके आस-पास मौजूद लोग, ब्रॉडकास्ट किए जा रहे मीडिया को सुन सकते हैं. हालांकि, इसके लिए उनके पास ऐसे ब्लूटूथ डिवाइस होने चाहिए जिन पर मीडिया चलाया जा सके"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"हो गया"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कॉपी किए गए टेक्स्ट को खारिज करें"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी किया गया यूज़र इंटरफ़ेस (यूआई) खारिज करें"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी किए गए टेक्स्ट में बदलाव करें"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी की गई इमेज में बदलाव करें"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"कॉन्टेंट को आस-पास मौजूद डिवाइस पर भेजें"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कैमरा और माइक बंद हैं"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट ऐप्लिकेशन"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट करें"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट बदलें"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"कोई जानकारी नहीं"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 9af07bc65b8c..a156b0c43ca6 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"बंद है"</item>
<item msgid="460891964396502657">"चालू है"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"उपलब्ध नहीं है"</item>
+ <item msgid="8014986104355098744">"बंद है"</item>
+ <item msgid="5966994759929723339">"चालू है"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 68afcba3a291..c992d24d9c24 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi za dovršetak"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Otključano pomoću lica. Pritisnite ikonu otključavanja da biste nastavili."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano pomoću lica. Pritisnite da biste nastavili."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste nastavili."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentičnost provjerena"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite uzorak"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. zakretanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Čuvar zaslona"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup fotoaparatu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
@@ -315,6 +319,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Prijeđite prstom prema gore da biste otvorili"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pritisnite ikonu otključavanja da biste otvorili"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Otključano pomoću lica. Pritisnite ikonu otključavanja da biste otvorili."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Otključano pomoću lica. Pritisnite da biste otvorili."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice je prepoznato. Pritisnite da biste otvorili."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste otvorili."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Pomicanje ulijevo"</item>
<item msgid="5558598599408514296">"Pomicanje prema dolje"</item>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Način rada za goste"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Upotrebljavate način rada za goste"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ako dodate novog korisnika, napustit ćete način rada za goste i izbrisat će se svi podaci i aplikacije iz trenutačne gostujuće sesije."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Dosegnuto je ograničenje korisnika"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozorenja"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snimke zaslona"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Općenite poruke"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant aplikacije"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Postavljanje"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje zaslona"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste emitirali ovu sesiju, otvorite aplikaciju."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audioizlaz."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako emitiranje funkcionira"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitiranje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u blizini s kompatibilnim Bluetooth uređajima mogu slušati medije koje emitirate"</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog sučelja"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji uređaju u blizini"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat i mikrofon su isključeni"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, vaše će se trenutačno emitiranje zaustaviti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiranje aplikacije <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promjena izlaza"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index a057c48bbec9..b69b06419281 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupno"</item>
+ <item msgid="8014986104355098744">"Isključeno"</item>
+ <item msgid="5966994759929723339">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7def3764f365..eee3f488dff3 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Megerősítve"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Koppintson a Megerősítés lehetőségre"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Zárolás arccal feloldva. Folytatás: Feloldásra koppintás."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Zárolás arccal feloldva. Koppintson a folytatáshoz."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Arc felismerve. Koppintson a folytatáshoz."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Arc felismerve. A folytatáshoz koppintson a Feloldásra."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Hitelesítve"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-kód használata"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Minta használata"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyővédő"</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>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Csúsztasson felfelé a megnyitáshoz"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Az eszköz használatához nyomja meg a feloldás ikonját"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Zárolás arccal feloldva. Eszköz használata: Feloldás ikon."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Zárolás arccal feloldva. Koppintson az eszköz használatához."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Arc felismerve. Koppintson az eszköz használatához."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Arc felismerve. Eszköz használata: Feloldás ikon."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mozgatás balra"</item>
<item msgid="5558598599408514296">"Mozgatás lefelé"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Igen, folytatom"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Vendég mód"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Vendég módban van"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Új felhasználó felvételével kilép a vendég módból, és az aktuális vendégmunkamenetből származó összes alkalmazás és adat törlődik majd."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Maximális felhasználószám elérve"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Legfeljebb <xliff:g id="COUNT">%d</xliff:g> felhasználót adhat hozzá.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Értesítések"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akkumulátor"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Képernyőképek"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Általános üzenetek"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Azonnali alkalmazások"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Beállítás"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Tárhely"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tippek"</string>
<string name="instant_apps" msgid="8337185853050247304">"Azonnali alkalmazások"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"helyadatok"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"képernyőrögzítés"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"A munkamenet átküldéséhez nyissa meg az alkalmazást."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ismeretlen alkalmazás"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Átküldés leállítása"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Rendelkezésre álló eszközök a hangkimenethez."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Közvetítés"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"A közelben tartózkodó, kompatibilis Bluetooth-eszközzel rendelkező személyek meghallgathatják az Ön közvetített médiatartalmait"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Kész"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Másolva"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Forrás: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Vágólapra másolt szöveg elvetése"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Másolási UI elvetése"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Vágólapra másolt szöveg szerkesztése"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Vágólapra másolt kép szerkesztése"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Küldés közeli eszközre"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A kamera és a mikrofon ki vannak kapcsolva"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sugárzás"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Kimenet módosítása"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ismeretlen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index 47109a334e6d..050bc14d54ff 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Ki"</item>
<item msgid="460891964396502657">"Be"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nem áll rendelkezésre"</item>
+ <item msgid="8014986104355098744">"Ki"</item>
+ <item msgid="5966994759929723339">"Be"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 500afd1ace81..838f75be7eb3 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Հաստատվեց"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ավարտելու համար հպեք «Հաստատել»"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Ապակողպվել է դեմքով։ Սեղմեք ապակողպման պատկերակը։"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ապակողպվել է դեմքով։ Սեղմեք շարունակելու համար։"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Դեմքը ճանաչվեց։ Սեղմեք շարունակելու համար։"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Դեմքը ճանաչվեց։ Սեղմեք ապակողպման պատկերակը։"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Նույնականացված է"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Օգտագործել PIN կոդ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Օգտագործել նախշ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Էկրանապահ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Տեսախցիկի հասանելիություն"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Խոսափողի հասանելիություն"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Հասանելի է"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Բացելու համար սահեցրեք վերև"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Բացեք՝ սեղմելով ապակողպման պատկերակը"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Ապակողպվել է դեմքով։ Բացեք՝ սեղմելով ապակողպման պատկերակը։"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ապակողպվել է դեմքով։ Սեղմեք բացելու համար։"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Դեմքը ճանաչվեց։ Սեղմեք բացելու համար։"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Դեմքը ճանաչվեց։ Բացելու համար սեղմեք ապակողպման պատկերակը։"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Տեղափոխել ձախ"</item>
<item msgid="5558598599408514296">"Տեղափոխել ներքև"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Վերսկսել"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Այո, շարունակել"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Հյուրի ռեժիմ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Դուք հյուրի ռեժիմում եք"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ավելացնելով նոր օգտատեր՝ դուք դուրս կգաք հյուրի ռեժիմից։ Հյուրի ընթացիկ աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն։"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Սահմանաչափը սպառված է"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Հնարավոր է ավելացնել առավելագույնը <xliff:g id="COUNT">%d</xliff:g> օգտատեր։</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ծանուցումներ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Մարտկոց"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Սքրինշոթներ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ընդհանուր հաղորդագրություններ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Ակնթարթային հավելվածներ"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Կարգավորում"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Տարածք"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Հուշումներ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ակնթարթային հավելվածներ"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"էկրանի տեսագրում"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Այս աշխատաշրջանը հեռարձակելու համար բացեք հավելվածը"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Անհայտ հավելված"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Կանգնեցնել հեռարձակումը"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Հասանելի սարքեր ձայնի արտածման համար։"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Հեռարձակում"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ձեր մոտակայքում գտնվող՝ համատեղելի Bluetooth սարքերով մարդիկ կարող են լսել մեդիա ֆայլերը, որոնք դուք հեռարձակում եք։"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Պատրաստ է"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածից"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Հեռացնել պատճենված տեքստը"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Փակել պատճենների միջերեսը"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Փոփոխել պատճենված տեքստը"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Փոփոխել պատճենված պատկերը"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ուղարկել մոտակա սարքի"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Զարթուցիչը դրված է"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Տեսախցիկը և խոսափողն անջատված են"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Հեռարձակում"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Հեռարձակել <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Փոխել աուդիո ելքը"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Անհայտ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index a78b7a10e58e..6015fbd75b3c 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Անջատված է"</item>
<item msgid="460891964396502657">"Միացված է"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Հասանելի չէ"</item>
+ <item msgid="8014986104355098744">"Անջատված է"</item>
+ <item msgid="5966994759929723339">"Միացված է"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 91655cbc991c..851a4978b8fe 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Dikonfirmasi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketuk Konfirmasi untuk menyelesaikan"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Kunci dibuka dengan wajah. Tekan ikon buka kunci untuk melanjutkan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Kunci dibuka dengan wajah. Tekan untuk melanjutkan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dikenali. Tekan untuk melanjutkan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dikenali. Tekan ikon buka kunci untuk melanjutkan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Diautentikasi"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan pola"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Geser ke atas untuk membuka"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Tekan ikon buka kunci untuk membuka"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Kunci dibuka dengan wajah. Tekan ikon buka kunci untuk membuka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Kunci dibuka dengan wajah. Tekan untuk membuka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Wajah dikenali. Tekan untuk membuka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Wajah dikenali. Tekan ikon buka kunci untuk membuka."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Pindah ke kiri"</item>
<item msgid="5558598599408514296">"Pindah ke bawah"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, lanjutkan"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mode tamu"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Anda sedang menggunakan mode tamu"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Menambahkan pengguna baru akan membuat Anda keluar dari mode tamu dan menghapus semua aplikasi serta data dari sesi tamu saat ini."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Batas pengguna tercapai"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Anda dapat menambahkan hingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Notifikasi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterai"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Pesan Umum"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplikasi Instan"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Penyiapan"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Penyimpanan"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Petunjuk"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikasi Instan"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"perekaman layar"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Buka aplikasi untuk mentransmisikan sesi ini."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikasi tidak dikenal"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hentikan transmisi"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Perangkat yang tersedia untuk output audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siaran"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang di dekat Anda dengan perangkat Bluetooth yang kompatibel dapat mendengarkan media yang sedang Anda siarkan"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Selesai"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Dari <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Tutup teks yang disalin"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Tutup UI salin"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit gambar yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Kirim ke perangkat di sekitar"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon nonaktif"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ubah output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tidak diketahui"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 6f81b29990cd..b8eb2f7d654e 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Nonaktif"</item>
<item msgid="460891964396502657">"Aktif"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Tidak tersedia"</item>
+ <item msgid="8014986104355098744">"Nonaktif"</item>
+ <item msgid="5966994759929723339">"Aktif"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 1df970fbfb8a..5a9a1a86b743 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Staðfest"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ýttu á „Staðfesta“ til að ljúka"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Opnað með andliti. Ýttu á táknið taka úr lás til að halda áfram."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Opnað með andliti. Ýttu til að halda áfram."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Andlitið var greint. Ýttu til að halda áfram."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Andlitið var greint. Ýttu á opnunartáknið til að halda áfr."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Auðkennt"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Nota PIN-númer"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Nota mynstur"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skjávari"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Aðgangur að myndavél"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Aðgangur að hljóðnema"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tiltækt"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Strjúktu upp til að opna"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Ýttu á táknið til að taka úr lás til að opna"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Opnað með andliti. Ýttu á táknið taka úr lás til að opna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Opnað með andliti. Ýttu til að opna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Andlitið var greint. Ýttu til að opna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Andlitið var greint. Ýttu á opnunartáknið til að opna."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Færa til vinstri"</item>
<item msgid="5558598599408514296">"Færa niður"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Já, halda áfram"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gestastilling"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Þú ert í gestastillingu"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Þegar nýjum notanda er bætt við er gestastillingu lokað og öllum forritum og gögnum úr núverandi gestalotu eytt."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Notandahámarki náð"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Þú getur bætt við allt að <xliff:g id="COUNT">%d</xliff:g> notanda.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Tilkynningar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Rafhlaða"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skjámyndir"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Almenn skilaboð"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Skyndiforrit"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Uppsetning"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Geymslurými"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vísbendingar"</string>
<string name="instant_apps" msgid="8337185853050247304">"Skyndiforrit"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"myndavél"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"staðsetning"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"hljóðnemi"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"skjáupptaka"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Opnaðu forritið til að senda þessa lotu út."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Óþekkt forrit"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stöðva útsendingu"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tæki í boði fyrir hljóðúttak."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Útsending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Fólk nálægt þér með samhæf Bluetooth-tæki getur hlustað á efnið sem þú sendir út"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Lokið"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Afritað"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Frá <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hunsa afritaðan texta"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Loka afriti notendaviðmóts"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Breyta afrituðum texta"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Breyta afritaðri mynd"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Senda í nálægt tæki"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Slökkt á myndavél og hljóðnema"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Útsending í gangi"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Senda út <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skipta um úttak"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Óþekkt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 29bce8257913..12dd776a357c 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Slökkt"</item>
<item msgid="460891964396502657">"Kveikt"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ekki í boði"</item>
+ <item msgid="8014986104355098744">"Slökkt"</item>
+ <item msgid="5966994759929723339">"Kveikt"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9f2b56e2f60b..270dc0fd2fde 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confermato"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tocca Conferma per completare"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Sbloccato con il volto. Premi l\'icona Sblocca e continua."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Sbloccato con il volto. Premi per continuare."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Volto riconosciuto. Premi per continuare."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Volto riconosciuto. Premi l\'icona Sblocca e continua."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticazione eseguita"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizza PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usa sequenza"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Salvaschermo"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Accesso alla fotocamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accesso al microfono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibile"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Scorri verso l\'alto per aprire"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Premi l\'icona Sblocca per aprire"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Sbloccato con il volto. Premi l\'icona Sblocca per aprire."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Sbloccato con il volto. Premi per aprire."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Volto riconosciuto. Premi per aprire."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Volto riconosciuto. Premi l\'icona Sblocca per aprire."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Sposta a sinistra"</item>
<item msgid="5558598599408514296">"Sposta giù"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sì, continua"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modalità Ospite"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Sei in modalità Ospite"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Se aggiungi un nuovo utente, la modalità Ospite viene disattivata e vengono eliminati tutti i dati e le app della sessione Ospite corrente."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Avvisi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Messaggi generali"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"App istantanee"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurazione"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Spazio di archiviazione"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Suggerimenti"</string>
<string name="instant_apps" msgid="8337185853050247304">"App istantanee"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotocamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posizione"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfono"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"Registraz. schermo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per trasmettere questa sessione devi aprire l\'app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App sconosciuta"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Interrompi trasmissione"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivi disponibili per l\'uscita audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annuncio"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Le persone vicine a te che hanno dispositivi Bluetooth compatibili possono ascoltare i contenuti multimediali che stai trasmettendo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fine"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiato"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Da <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignora il testo copiato"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora copia UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifica testo copiato"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifica immagine copiata"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Invia a dispositivo nelle vicinanze"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}other{# notifiche}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia uscita"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index 757a866463e6..5ec557bbaf7d 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Non disponibile"</item>
+ <item msgid="8014986104355098744">"Off"</item>
+ <item msgid="5966994759929723339">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 89e5d23d166d..ec62a0171357 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"הנעילה בוטלה בזיהוי פנים. להמשך, לוחצים על סמל ביטול הנעילה."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"הנעילה בוטלה באמצעות זיהוי הפנים. יש ללחוץ כדי להמשיך."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"הפנים זוהו. יש ללחוץ כדי להמשיך."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"הפנים זוהו. להמשך יש ללחוץ על סמל ביטול הנעילה."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"מאומת"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"שימוש בקוד אימות"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"שימוש בקו ביטול נעילה"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"סיבוב אוטומטי"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"סיבוב אוטומטי של המסך"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"שומר מסך"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"גישה למצלמה"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"גישה למיקרופון"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"יש גישה"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"צריך להחליק כדי לפתוח"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"לפתיחה, לוחצים על סמל ביטול הנעילה"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"הנעילה בוטלה בזיהוי פנים. פותחים בלחיצה על סמל ביטול הנעילה."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"הנעילה בוטלה באמצעות זיהוי הפנים. יש ללחוץ כדי לפתוח."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"הפנים זוהו. יש ללחוץ כדי לפתוח."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"הפנים זוהו. יש ללחוץ על סמל ביטול הנעילה כדי לפתוח."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"הזזה שמאלה"</item>
<item msgid="5558598599408514296">"הזזה למטה"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"סשן חדש"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"כן, להמשיך"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"מצב אורח"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"התחברת במצב אורח"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"הוספת משתמש חדש תגרום ליציאה ממצב האורח ותמחק את כל האפליקציות והנתונים מהגלישה הנוכחית כאורח."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"הגעת למגבלת המשתמשים שניתן להוסיף"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="two">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"התראות"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"סוללה"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"צילומי מסך"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"הודעות כלליות"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"אפליקציות ללא התקנה"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"הגדרה"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"אחסון"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"טיפים"</string>
<string name="instant_apps" msgid="8337185853050247304">"אפליקציות ללא התקנה"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"מצלמה"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"מיקום"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"מיקרופון"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"הקלטת המסך"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‏כדי להעביר (cast) את הסשן הזה, צריך לפתוח את האפליקציה."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"אפליקציה לא ידועה"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‏עצירת ההעברה (casting)"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"מכשירים זמינים לפלט אודיו."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"שידור"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏אנשים בקרבת מקום עם מכשירי Bluetooth תואמים יכולים להאזין למדיה שמשודרת על ידך"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"סיום"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"הועתק"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"המקור: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"מחיקה של הטקסט שהועתק"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ביטול של העתקת ממשק המשתמש"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"עריכת הטקסט שהועתק"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"עריכת התמונה שהועתקה"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"שליחה למכשיר בקרבת מקום"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}two{# התראות}many{# התראות}other{# התראות}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"שידור"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"שידור תוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"שינוי הפלט"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"לא ידוע"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 46be20c1f64d..91577b81a5d3 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"כבוי"</item>
<item msgid="460891964396502657">"פועל"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"לא זמין"</item>
+ <item msgid="8014986104355098744">"כבוי"</item>
+ <item msgid="5966994759929723339">"מופעל"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index c092dbd7b359..79e389fccbf0 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認しました"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"完了するには [確認] をタップしてください"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"顔でロック解除しました。ロック解除アイコンを押して続行します。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"顔でロック解除しました。押して続行してください。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"顔を認識しました。押して続行してください。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"顔を認識しました。ロック解除アイコンを押して続行します。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"認証済み"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN を使用"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"パターンを使用"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"スクリーン セーバー"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"カメラへのアクセス"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"マイクへのアクセス"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"使用可能"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"開くには上にスワイプします"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ロック解除アイコンを押して開きます"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"顔でロック解除しました。ロック解除アイコンを押して開きます。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"顔でロック解除しました。押すと開きます。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"顔を認識しました。押すと開きます。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"顔を認識しました。ロック解除アイコンを押して開きます。"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"左に移動"</item>
<item msgid="5558598599408514296">"下に移動"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"続行"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ゲストモード"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ゲストモード使用中"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"新しいユーザーを追加するとゲストモードは終了し、現在のゲスト セッションからすべてのアプリとデータが削除されます。"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ユーザー数が上限に達しました"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">最大 <xliff:g id="COUNT">%d</xliff:g> 人のユーザーを追加できます。</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"アラート"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"バッテリー"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"スクリーンショット"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般メッセージ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"セットアップ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ストレージ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ヒント"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"カメラ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"現在地情報"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"マイク"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"画面の録画"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"このセッションをキャストするには、アプリを開いてください。"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明なアプリ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"キャストを停止"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"音声出力ができるデバイスです。"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ブロードキャストの仕組み"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ブロードキャスト"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth 対応デバイスを持っている付近のユーザーは、あなたがブロードキャストしているメディアを聴けます"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完了"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"コピーしました"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> から"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"コピーしたテキストを閉じる"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"コピー UI を閉じる"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"コピーしたテキストを編集"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"コピーした画像を編集"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"付近のデバイスに送信"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"アラームを設定しました"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"カメラとマイクが OFF です"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 件の通知}other{# 件の通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ブロードキャスト"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> のブロードキャストを停止しますか?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャストしたり、出力を変更したりすると、現在のブロードキャストが停止します。"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャスト"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"出力を変更"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index fd966da986b8..c2a3321dc19f 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"OFF"</item>
<item msgid="460891964396502657">"ON"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"使用不可"</item>
+ <item msgid="8014986104355098744">"OFF"</item>
+ <item msgid="5966994759929723339">"ON"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 81cff8f3fc87..3d15011fd395 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"დადასტურებული"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"დასასრულებლად შეეხეთ „დადასტურებას“"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"განიბლოკა სახით. გასაგრძელებლად დააჭირეთ განბლოკვის ხატულას."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"განიბლოკა სახით. დააჭირეთ გასაგრძელებლად."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ამოცნობილია სახით. დააჭირეთ გასაგრძელებლად."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ამოცნობილია სახით. გასაგრძელებლად დააჭირეთ განბლოკვის ხატულას."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ავტორიზებულია"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-კოდის გამოყენება"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ნიმუშის გამოყენება"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ეკრანმზოგი"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"კამერაზე წვდომა"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"მიკროფონზე წვდომა"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ხელმისაწვდომი"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"გასახსნელად გადაფურცლეთ ზემოთ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"გასახსნელად დააჭირეთ განბლოკვის ხატულას"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"განიბლოკა სახით. გასახსნელად დააჭირეთ განბლოკვის ხატულას."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"განიბლოკა სახით. დააჭირეთ გასახსნელად."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ამოცნობილია სახით. დააჭირეთ გასახსნელად."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ამოცნობილია სახით. გასახსნელად დააჭირეთ განბლოკვის ხატულას."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"მარცხნივ გადატანა"</item>
<item msgid="5558598599408514296">"ქვემოთ გადატანა"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"დიახ, გავაგრძელოთ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"სტუმრის რეჟიმი"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"თქვენ სტუმრის რეჟიმში ხართ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"თუ ახალ მომხმარებელს დაამატებთ, სტუმრის რეჟიმი დაიხურება და სტუმრის რეჟიმის მიმდინარე სესიიდან ყველა აპი და მონაცემი წაიშლება."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"მიღწეულია მომხმარებელთა ლიმიტი"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">შესაძლებელია <xliff:g id="COUNT">%d</xliff:g>-მდე მომხმარებლის დამატება.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"გაფრთხილებები"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ბატარეა"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ეკრანის ანაბეჭდები"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ზოგადი შეტყობინებები"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"მყისიერი აპები"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"დაყენება"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"მეხსიერება"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"მინიშნებები"</string>
<string name="instant_apps" msgid="8337185853050247304">"მყისიერი აპები"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"კამერა"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"მდებარეობა"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"მიკროფონი"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ეკრანის ჩაწერა"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ამ სესიის ტრანსლირებისთვის გახსენით აპი."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"უცნობი აპი"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ტრანსლირების შეწყვეტა"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ხელმისაწვდომი მოწყობილობები გამომავალი აუდიოსთვის."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ტრანსლირების მუშაობის პრინციპი"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ტრანსლაცია"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"თქვენთან ახლოს მყოფ ხალხს თავსებადი Bluetooth მოწყობილობით შეუძლიათ თქვენ მიერ ტრანსლირებული მედიის მოსმენა"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"მზადაა"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"კოპირებულია"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-დან"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"კოპირებული ტექსტის უარყოფა"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"მომხმარებლის ინტერფეისის ასლის გაუქმება"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"კოპირებული ტექსტის რედაქტირება"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"კოპირებული სურათის რედაქტირება"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ახლომახლო მოწყობილობაზე გაგზავნა"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"მაღვიძარა დაყენებულია"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"კამერა და მიკროფონი გამორთულია"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# შეტყობინება}other{# შეტყობინება}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"იწყებთ მაუწყებლობას"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"გსურთ <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ტრანსლაციის შეჩერება?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაციის შემთხვევაში ან აუდიოს გამოსასვლელის შეცვლისას, მიმდინარე ტრანსლაცია შეჩერდება"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაცია"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"აუდიოს გამოსასვლელის შეცვლა"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"უცნობი"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 0c7d5af29890..c95187404d48 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"გამორთვა"</item>
<item msgid="460891964396502657">"ჩართვა"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"მიუწვდომელია"</item>
+ <item msgid="8014986104355098744">"გამორთულია"</item>
+ <item msgid="5966994759929723339">"ჩართულია"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a4776dd82344..dbe910d9c74c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Расталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Аяқтау үшін \"Растау\" түймесін түртіңіз."</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Бет үлгісі арқылы ашылды. Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Бетпен ашылды. Жалғастыру үшін басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Бет танылды. Жалғастыру үшін басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Бет танылды. Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификацияланған"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодын пайдалану"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Өрнекті пайдалану"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Скринсейвер"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камераны пайдалану"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофонды пайдалану"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Қолжетімді"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Ашу үшін жоғары қарай сырғытыңыз."</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Ашу үшін құлыпты ашу белгішесін басыңыз."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Бет үлгісі арқылы ашылды. Ашу үшін құлыпты ашу белгішесін басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Бетпен ашылды. Ашу үшін басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Бет танылды. Ашу үшін басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Бет танылды. Ашу үшін құлыпты ашу белгішесін басыңыз."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Солға жылжыту"</item>
<item msgid="5558598599408514296">"Төмен жылжыту"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Иә, жалғастыру"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Қонақ режимі"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Сіз қонақ режиміндесіз"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Жаңа пайдаланушы қосылған кезде, қонақ режимі жабылады, ағымдағы қонақ сеансындағы барлық қолданба мен дерек жойылады."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Пайдаланушылар саны шегіне жетті"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> пайдаланушыға дейін енгізуге болады.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Ескертулер"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоттар"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Жалпы хабарлар"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Реттеу"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Жад"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Кеңестер"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геодерек"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"экранды бейнеге жазу"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бұл сеансты трансляциялау үшін қолданбаны ашыңыз."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгісіз қолданба"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Трансляцияны тоқтату"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио шығыс үшін қолжетімді құрылғылар бар."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Тарату"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Үйлесімді Bluetooth құрылғылары бар маңайдағы адамдар сіз таратып жатқан медиамазмұнды тыңдай алады."</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Дайын"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көшірілді"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасынан"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Көшірілген мәтінді жою"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көшіру интерфейсін жабу"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көшірілген мәтінді өңдеу"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көшірілген суретті өңдеу"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Маңайдағы құрылғыға жіберу"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Оятқыш орнатылды"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера мен микрофон өшірулі"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Таратуда"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын тарату"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудио шығысын өзгерту"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Белгісіз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index 546666327e69..c312b4957615 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Өшірулі"</item>
<item msgid="460891964396502657">"Қосулы"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Қолжетімді емес."</item>
+ <item msgid="8014986104355098744">"Өшірулі."</item>
+ <item msgid="5966994759929723339">"Қосулы."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 2319f9d6d43a..03d52036a1ec 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"បានបញ្ជាក់"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ចុច \"បញ្ជាក់\" ដើម្បីបញ្ចប់"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"បានដោះសោ​ដោយប្រើមុខ។ សូមចុចរូបដោះសោ ដើម្បីបន្ត។"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបន្ត។"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបន្ត។"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"បាន​ផ្ទៀងផ្ទាត់"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ប្រើកូដ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ប្រើ​លំនាំ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិល​ស្វ័យ​ប្រវត្តិ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ធាតុរក្សាអេក្រង់"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ការចូលប្រើ​កាមេរ៉ា"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ការចូលប្រើ​មីក្រូហ្វូន"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចចូលប្រើបាន"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"អូសឡើងលើ​ដើម្បីបើក"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ចុចរូបដោះសោ ដើម្បីបើក"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"បានដោះសោ​ដោយប្រើមុខ។ សូមចុចរូបដោះសោ ដើម្បីបើក។"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបើក។"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបើក។"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបើក។"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ផ្លាស់ទី​ទៅ​ឆ្វេង"</item>
<item msgid="5558598599408514296">"ផ្លាស់ទី​ចុះ​ក្រោម"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​វគ្គ​របស់​អ្នក​ទេ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើមសាជាថ្មី"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"បាទ​/ចាស ​បន្ត"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"មុខងារ​ភ្ញៀវ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"អ្នកស្ថិតនៅក្នុងមុខងារភ្ញៀវ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ការបញ្ចូលអ្នកប្រើប្រាស់ថ្មីនឹងធ្វើឱ្យចាកចេញពីមុខងារភ្ញៀវ និងលុបកម្មវិធីនិងទិន្នន័យទាំងអស់ចេញពីវគ្គភ្ញៀវបច្ចុប្បន្ន។"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"​បាន​ឈាន​ដល់ចំនួន​កំណត់អ្នកប្រើប្រាស់"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">អ្នកអាចបញ្ចូល​អ្នក​ប្រើប្រាស់បាន​រហូតដល់ <xliff:g id="COUNT">%d</xliff:g> នាក់។</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ការជូនដំណឹង"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ថ្ម"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"រូបថត​អេក្រង់"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"សារ​ទូទៅ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"កម្មវិធី​ប្រើ​ភ្លាមៗ"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ការរៀបចំ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ទំហំផ្ទុក"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ការ​សម្រួល"</string>
<string name="instant_apps" msgid="8337185853050247304">"កម្មវិធី​ប្រើ​ភ្លាមៗ"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"កាមេរ៉ា"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ទីតាំង"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"មីក្រូហ្វូន"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ការថតវីដេអូអេក្រង់"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មាន​ចំណងជើង"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"វិនដូ​ការពង្រីក"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ដើម្បីភ្ជាប់វគ្គនេះ សូមបើកកម្មវិធី។"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"កម្មវិធី​ដែលមិន​ស្គាល់"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"បញ្ឈប់ការភ្ជាប់"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ឧបករណ៍​ដែលអាច​ប្រើបាន​សម្រាប់ឧបករណ៍​បញ្ចេញ​សំឡេង។"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ការ​ផ្សាយ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"មនុស្សនៅជិត​អ្នកដែលមាន​ឧបករណ៍ប៊្លូធូស​ត្រូវគ្នា​អាចស្តាប់​មេឌៀ​ដែលអ្នកកំពុងផ្សាយបាន"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"រួចរាល់"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"បានចម្លង"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ពី <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ច្រានចោលអត្ថបទដែលបានចម្លង"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ច្រានចោល UI ចម្លង"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"កែអត្ថបទ​ដែលបានចម្លង"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"កែរូបភាព​ដែលបានចម្លង"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ផ្ញើទៅ​ឧបករណ៍​នៅជិត"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់​ម៉ោងរោទ៍"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"កាមេរ៉ា និង​មីក្រូហ្វូន​ត្រូវបានបិទ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការ​ជូន​ដំណឹង #}other{ការ​ជូនដំណឹង #}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ការផ្សាយ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ប្រសិនបើអ្នក​ផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹង​បញ្ឈប់"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ការផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ប្ដូរឧបករណ៍បញ្ចេញសំឡេង"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"មិនស្គាល់"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index f4830f5bbb75..ec748cfac142 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"បិទ"</item>
<item msgid="460891964396502657">"បើក"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"មិនមានទេ"</item>
+ <item msgid="8014986104355098744">"បិទ"</item>
+ <item msgid="5966994759929723339">"បើក"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index cfb0d24e5970..883a3880c577 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ಪೂರ್ಣಗೊಳಿಸಲು ದೃಢೀಕರಿಸಿ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಅನ್‌ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಅನ್‌ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ಪಿನ್ ಬಳಸಿ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ಪ್ಯಾಟರ್ನ್ ಬಳಸಿ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ಕ್ಯಾಮರಾ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ಮೈಕ್ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ಲಭ್ಯವಿದೆ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ತೆರೆಯಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ತೆರೆಯಲು ಅನ್‌ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ತೆರೆಯಲು ಅನ್‌ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ತೆರೆಯಲು ಒತ್ತಿ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ತೆರೆಯಲು ಒತ್ತಿ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ತೆರೆಯಲು ಅನ್‌ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</item>
<item msgid="5558598599408514296">"ಕೆಳಗೆ ಸರಿಸಿ"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ಹೌದು, ಮುಂದುವರಿಸಿ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ಅತಿಥಿ ಮೋಡ್"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ನೀವು ಅತಿಥಿ ಮೋಡ್‌ನಲ್ಲಿದ್ದೀರಿ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸುವುದರಿಂದ ಅತಿಥಿ ಮೋಡ್‌ನಿಂದ ನಿರ್ಗಮಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರಸ್ತುತ ಅತಿಥಿ ಸೆಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ಬಳಕೆದಾರರ ಮಿತಿ ತಲುಪಿದೆ"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">ನೀವು <xliff:g id="COUNT">%d</xliff:g> ಬಳಕೆದಾರರವರೆಗೆ ಸೇರಿಸಬಹುದು.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ಅಲರ್ಟ್‌ಗಳು"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ಬ್ಯಾಟರಿ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳು"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ಸೆಟಪ್"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ಸಂಗ್ರಹಣೆ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ಸುಳಿವುಗಳು"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ಕ್ಯಾಮರಾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ಸ್ಥಳ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ಮೈಕ್ರೋಫೋನ್‌"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ಈ ಸೆಶನ್ ಕಾಸ್ಟ್ ಮಾಡಲು, ಆ್ಯಪ್ ಅನ್ನು ತೆರೆಯಿರಿ."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ಅಪರಿಚಿತ ಆ್ಯಪ್"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ಆಡಿಯೋ ಔಟ್‌ಪುಟ್‌ಗಾಗಿ ಲಭ್ಯವಿರುವ ಸಾಧನಗಳು."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ಪ್ರಸಾರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ಪ್ರಸಾರ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ಹೊಂದಾಣಿಕೆಯಾಗುವ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಹೊಂದಿರುವ ಸಮೀಪದಲ್ಲಿರುವ ಜನರು ನೀವು ಪ್ರಸಾರ ಮಾಡುತ್ತಿರುವ ಮಾಧ್ಯಮವನ್ನು ಆಲಿಸಬಹುದು"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ಮುಗಿದಿದೆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ನಕಲಿಸಲಾಗಿದೆ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ನಿಂದ"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI ನಕಲನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ನಕಲಿಸಿದ ಚಿತ್ರವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಿ"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ ಆಫ್ ಆಗಿದೆ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ಅಧಿಸೂಚನೆ}one{# ಅಧಿಸೂಚನೆಗಳು}other{# ಅಧಿಸೂಚನೆಗಳು}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ಪ್ರಸಾರ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಬೇಕೆ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ನೀವು <xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿದರೆ ಅಥವಾ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿದರೆ, ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪ್ರಸಾರವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ಔಟ್‌ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ಅಪರಿಚಿತ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 5cf2f5c2661e..864a607c8a39 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ಆಫ್ ಮಾಡಿ"</item>
<item msgid="460891964396502657">"ಆನ್ ಮಾಡಿ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ಲಭ್ಯವಿಲ್ಲ"</item>
+ <item msgid="8014986104355098744">"ಆಫ್ ಮಾಡಿ"</item>
+ <item msgid="5966994759929723339">"ಆನ್ ಮಾಡಿ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 8e6d2ca6c87d..8aaf37a36fed 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"확인함"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"완료하려면 확인을 탭하세요."</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 잠금 해제 아이콘을 누르세요."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 누르세요."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"얼굴이 인식되었습니다. 계속하려면 누르세요."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"얼굴이 인식되었습니다. 계속하려면 아이콘을 누르세요."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"인증됨"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN 사용"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"패턴 사용"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"화면 보호기"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"사용 가능"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"위로 스와이프하여 열기"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"기기를 열려면 잠금 해제 아이콘을 누르세요."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"얼굴 인식으로 잠금 해제되었습니다. 기기를 열려면 잠금 해제 아이콘을 누르세요."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"얼굴 인식으로 잠금 해제되었습니다. 열려면 누르세요."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"얼굴이 인식되었습니다. 열려면 누르세요."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"얼굴이 인식되었습니다. 열려면 잠금 해제 아이콘을 누르세요."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"왼쪽으로 이동"</item>
<item msgid="5558598599408514296">"아래로 이동"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"계속 진행"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"게스트 모드"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"게스트 모드 사용 중"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"새로운 사용자를 추가하면 게스트 모드가 종료되고 기존 게스트 세션의 모든 앱과 데이터가 삭제됩니다."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"사용자 제한 도달"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">사용자를 <xliff:g id="COUNT">%d</xliff:g>명까지 추가할 수 있습니다.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"알림"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"배터리"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"스크린샷"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"일반 메시지"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"인스턴트 앱"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"설정"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"저장용량"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"힌트"</string>
<string name="instant_apps" msgid="8337185853050247304">"인스턴트 앱"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"카메라"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"위치"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"마이크"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"화면 녹화"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"세션을 전송하려면 앱을 열어 주세요"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"알 수 없는 앱"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"전송 중지"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"오디오 출력에 사용 가능한 기기입니다."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"브로드캐스트"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"호환되는 블루투스 기기를 가진 근처의 사용자가 내가 브로드캐스트 중인 미디어를 수신 대기할 수 있습니다."</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"완료"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"복사됨"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"복사한 위치: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"복사된 텍스트 닫기"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI 복사 닫기"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"복사된 텍스트 편집"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"복사된 이미지 편집"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"근처 기기에 전송"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"알람이 설정되었습니다."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"카메라 및 마이크가 사용 중지되었습니다."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"방송 중"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 방송"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"출력 변경"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"알 수 없음"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 3244ffaec49c..c52c17cedc32 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"꺼짐"</item>
<item msgid="460891964396502657">"켜짐"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"사용 불가"</item>
+ <item msgid="8014986104355098744">"꺼짐"</item>
+ <item msgid="5966994759929723339">"켜짐"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9600ec26a1e4..cf3f331c4489 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ырасталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Бүтүрүү үчүн \"Ырастоо\" баскычын басыңыз"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Кулпусун жүзүңүз менен ачтыңыз. Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Кулпусун жүзүңүз менен ачтыңыз. Улантуу үчүн басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Жүз таанылды. Улантуу үчүн басыңыз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Жүз таанылды. Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аныктыгы текшерилди"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодду колдонуу"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Графикалык ачкычты колдонуу"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Көшөгө"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камера"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофон"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Жеткиликтүү"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Ачуу үчүн өйдө сүрүңүз"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Ачуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Кулпусун жүзүңүз менен ачтыңыз. Ачуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Кулпусун жүзүңүз менен ачтыңыз. Ачуу үчүн басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Жүз таанылды. Ачуу үчүн басыңыз."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Жүз таанылды. Ачуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Солго жылдыруу"</item>
<item msgid="5558598599408514296">"Төмөн жылдыруу"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ооба, уланта берели"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Конок режими"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Конок режиминдесиз"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Жаңы колдонуучуну кошсоңуз, конок режими жабылып, учурдагы конок сеансындагы бардык колдонмолор жана башка нерселер өчүп калат."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Дагы колдонуучу кошууга болбойт"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> колдонуучуга чейин кошууга болот.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Эскертүүлөр"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоттор"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Жалпы билдирүүлөр"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Ыкчам ачылуучу колдонмолор"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Тууралоо"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Сактагыч"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Кеңештер"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ыкчам ачылуучу колдонмолор"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"жайгашкан жер"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"экранды жаздыруу"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөк кошуу"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бул сеансты тышкы экранга чыгаруу үчүн колдонмону ачыңыз."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгисиз колдонмо"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Тышкы экранга чыгарууну токтотуу"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио чыгаруу үчүн жеткиликтүү түзмөктөр."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Кабарлоо"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Шайкеш Bluetooth түзмөктөрү болгон жакын жердеги кишилер кабарлап жаткан медиаңызды уга алышат"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Бүттү"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көчүрүлдү"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосунан"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Көчүрүлгөн текстти жабуу"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көчүрмөнү жабуу интерфейси"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көчүрүлгөн текстти түзөтүү"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көчүрүлгөн сүрөттү түзөтүү"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Жакын жердеги түзмөккө жөнөтүү"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ойготкуч коюлду"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера жана микрофон өчүк"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Кеңири таратуу"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарлоо"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудионун чыгуусун өзгөртүү"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Белгисиз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index 5518fccac6ee..f872926aa945 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Өчүк"</item>
<item msgid="460891964396502657">"Күйүк"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Жеткиликсиз"</item>
+ <item msgid="8014986104355098744">"Өчүк"</item>
+ <item msgid="5966994759929723339">"Күйүк"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 13b1484562db..14ba7f715cd6 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ຢືນຢັນແລ້ວ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ແຕະຢືນຢັນເພື່ອສຳເລັດ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ໃຊ້ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ໃຊ້ຮູບແບບ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນ​ອັດ​ຕະ​ໂນ​ມັດ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ພາບພັກໜ້າຈໍ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ການເຂົ້າເຖິງກ້ອງຖ່າຍຮູບ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ການເຂົ້າເຖິງໄມ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ສາມາດໃຊ້ໄດ້"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ປັດຂຶ້ນເພື່ອເປີດ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ກົດໄອຄອນປົດລັອກເພື່ອເປີດ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອເປີດ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອເປີດ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອເປີດ."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອເປີດ."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ຍ້າຍໄປຊ້າຍ"</item>
<item msgid="5558598599408514296">"ຍ້າຍລົງ"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"​ຕົກ​ລົງ, ດຳ​ເນີນ​ການ​ຕໍ່"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ໂໝດແຂກ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ທ່ານກຳລັງຢູ່ໃນໂໝດແຂກ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ການເພີ່ມຜູ້ໃຊ້ໃໝ່ຈະອອກຈາກໂໝດແຂກ ແລະ ລຶບແອັບ ແລະ ຂໍ້ມູນທັງໝົດອອກຈາກເຊດຊັນແຂກປັດຈຸບັນ."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">ທ່ານສາມາດເພີ່ມໄດ້ສູງສຸດ <xliff:g id="COUNT">%d</xliff:g> ຄົນ.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ການແຈ້ງເຕືອນ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ແບັດເຕີຣີ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ຮູບຖ່າຍໜ້າຈໍ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ຂໍ້ຄວາມທົ່ວໄປ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"ອິນສະແຕນແອັບ"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ຕັ້ງຄ່າ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ບ່ອນເກັບຂໍ້ມູນ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ຄຳໃບ້"</string>
<string name="instant_apps" msgid="8337185853050247304">"ອິນສະແຕນແອັບ"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ກ້ອງຖ່າຍຮູບ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ສະຖານທີ່"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ໄມໂຄຣໂຟນ"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ການບັນທຶກໜ້າຈໍ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ເພື່ອສົ່ງສັນຍານເຊດຊັນນີ້, ກະລຸນາເປີດແອັບ."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ແອັບທີ່ບໍ່ຮູ້ຈັກ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ຢຸດການສົ່ງສັນຍານ"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ອຸປະກອນທີ່ສາມາດໃຊ້ໄດ້ສຳລັບເອົ້າພຸດສຽງ."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ອອກອາກາດ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ຄົນທີ່ຢູ່ໃກ້ທ່ານທີ່ມີອຸປະກອນ Bluetooth ທີ່ເຂົ້າກັນໄດ້ຈະສາມາດຟັງມີເດຍທີ່ທ່ານກຳລັງອອກອາກາດຢູ່ໄດ້"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ແລ້ວໆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ຈາກ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ປິດຂໍ້ຄວາມທີ່ສຳເນົາໄວ້"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ປິດການສຳເນົາສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ໄວ້"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ແກ້ໄຂຂໍ້ຄວາມທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ແກ້ໄຂຮູບທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ສົ່ງໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ປິດກ້ອງຖ່າຍຮູບ ແລະ ໄມແລ້ວ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ກຳລັງອອກອາກາດ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ປ່ຽນເອົ້າພຸດ"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ບໍ່ຮູ້ຈັກ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index c6b7e6c6e74d..6ae37e472b0c 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ປິດ"</item>
<item msgid="460891964396502657">"ເປີດ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
+ <item msgid="8014986104355098744">"ປິດ"</item>
+ <item msgid="5966994759929723339">"ເປີດ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6f740ed6e180..68c523238f5b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Patvirtinta"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Paliesk. „Patvirtinti“, kad užbaigtumėte"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Atrakinta pagal veidą. Pasp. atrak. pikt., kad tęstumėte."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Veidas atpažintas. Paspauskite, jei norite tęsti."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Veidas atpažintas. Tęskite paspaudę atrakinimo piktogramą."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikuota"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Naudoti PIN kodą"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Naudoti atrakinimo piešinį"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekrano užsklanda"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Prieiga prie fotoaparato"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Prieiga prie mikrofono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Pasiekiama"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Perbraukite aukštyn, kad atidarytumėte"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Paspauskite atrakinimo piktogramą, kad atidarytumėte"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Atrakinta pagal veidą. Pasp. atr. pikt., kad atidarytumėte."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Atrakinta pagal veidą. Paspauskite, kad atidarytumėte."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Veidas atpažintas. Paspauskite, kad atidarytumėte."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Veidas atpažintas. Atidarykite paspaudę atrakin. piktogramą."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Perkelti kairėn"</item>
<item msgid="5558598599408514296">"Perkelti žemyn"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Taip, tęsti"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Svečio režimas"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Naudojatės svečio režimu"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Pridėjus naują naudotoją, bus išeita iš svečio režimo ir iš dabartinės svečio sesijos bus ištrintos visos programos ir duomenys."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Pasiekta naudotojų riba"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojo.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Įspėjimai"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akumuliatorius"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekrano kopijos"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Bendrieji pranešimai"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Akimirksniu įkeliamos programos"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Sąranka"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Saugykla"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Užuominos"</string>
<string name="instant_apps" msgid="8337185853050247304">"Akimirksniu įkeliamos programos"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparatą"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vietovę"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoną"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekrano įrašymas"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jei norite perduoti šį seansą, atidarykite programą."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nežinoma programa"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sustabdyti perdavimą"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Pasiekiami garso išvesties įrenginiai."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transliacija"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Netoliese esantys žmonės, turintys suderinamus „Bluetooth“ įrenginius, gali klausyti jūsų transliuojamos medijos"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Atlikta"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nukopijuota"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iš „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Atsisakyti nukopijuoto teksto"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Atsisakyti kopijavimo NS"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redaguoti nukopijuotą tekstą"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redaguoti nukopijuotą vaizdą"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Siųsti į įrenginį netoliese"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Vaizdo kamera ir mikrofonas išjungti"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transliavimas"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transliuoti „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Keisti išvestį"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nežinoma"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 3e289e1f21ce..03d98c42ff19 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Išjungta"</item>
<item msgid="460891964396502657">"Įjungta"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nepasiekiama"</item>
+ <item msgid="8014986104355098744">"Išjungta"</item>
+ <item msgid="5966994759929723339">"Įjungta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 38c095f17de2..26f375447d48 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Apstiprināts"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lai pabeigtu, pieskarieties Apstiprināt"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Atbloķēta ar seju. Turpināt: nospiediet atbloķēšanas ikonu."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ierīce atbloķēta ar seju. Nospiediet, lai turpinātu."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Seja atpazīta. Nospiediet, lai turpinātu."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Seja atpazīta. Lai turpinātu, nospiediet atbloķēšanas ikonu."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikācija veikta"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Izmantot PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Izmantot kombināciju"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekrānsaudzētājs"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofons"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Piekļuve atļauta"</string>
@@ -315,6 +319,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Velciet augšup, lai atvērtu"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Lai atvērtu, nospiediet atbloķēšanas ikonu"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Atbloķēta ar seju. Atvērt: nospiediet atbloķēšanas ikonu."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ierīce atbloķēta ar seju. Nospiediet, lai atvērtu."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Seja atpazīta. Nospiediet, lai atvērtu."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Seja atpazīta. Lai atvērtu, nospiediet atbloķēšanas ikonu."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Pārvietojiet pirkstu pa kreisi"</item>
<item msgid="5558598599408514296">"Pārvietojiet pirkstu lejup"</item>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jā, turpināt"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Viesa režīms"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Jūs izmantojat viesa režīmu"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ja pievienosiet jaunu lietotāju, viesa režīms tiks aizvērts un visas pašreizējās viesa sesijas lietotnes un dati tiks dzēsti."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Sasniegts lietotāju ierobežojums"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="zero">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotājus.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Brīdinājumi"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Akumulators"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekrānuzņēmumi"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Vispārīgi ziņojumi"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Tūlītējās lietotnes"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Iestatīšana"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Krātuve"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Padomi"</string>
<string name="instant_apps" msgid="8337185853050247304">"Tūlītējās lietotnes"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"atrašanās vieta"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofons"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekrāna ierakstīšana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Lai apraidītu šo sesiju, lūdzu, atveriet lietotni."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nezināma lietotne"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Apturēt apraidi"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio izvadei pieejamās ierīces."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Apraide"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Tuvumā esošās personas ar saderīgām Bluetooth ierīcēm var klausīties jūsu apraidīto multivides saturu."</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gatavs"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nokopēts"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"No lietotnes <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Nerādīt kopēto tekstu"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Noraidīt ar kopēšanu saistīto lietotāja saskarnes elementu"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediģēt nokopēto tekstu"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediģēt nokopēto attēlu"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Sūtīt uz tuvumā esošu ierīci"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera un mikrofons ir izslēgti"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Notiek apraidīšana"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraide"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Izvades maiņa"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nezināms"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index eb210c24bb50..6e9264d2a347 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Izslēgts"</item>
<item msgid="460891964396502657">"Ieslēgts"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nav pieejams"</item>
+ <item msgid="8014986104355098744">"Izslēgts"</item>
+ <item msgid="5966994759929723339">"Ieslēgts"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 842cae816040..e799c92b871b 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Допрете „Потврди“ за да се заврши"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Отклучено со лице. Притиснете ја иконата за отклучување за да продолжите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отклучено со лице. Притиснете за да продолжите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето е препознаено. Притиснете за да продолжите."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето е препознаено. Притиснете ја иконата за отклучување за да продолжите."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Проверена"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користи PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користи шема"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заштитник на екран"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Пристап до камерата"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Пристап до микрофонот"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Дозволен"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Повлечете за да отворите"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Притиснете ја иконата за отклучување за да отворите"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Отклучено со лице. Притиснете ја иконата за отклучување за да отворите."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Отклучено со лице. Притиснете за да отворите."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицето е препознаено. Притиснете за да отворите."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицето е препознаено. Притиснете ја иконата за отклучување за да отворите."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Премести налево"</item>
<item msgid="5558598599408514296">"Премести надолу"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжи"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Режим на гостин"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Користите режим на гостин"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ако додадете нов корисник, ќе излезете од режимот на гостин и ќе ги избришете сите апликации и податоци од тековната гостинска сесија."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнато ограничување на корисник"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Може да додадете најмногу <xliff:g id="COUNT">%d</xliff:g> корисник.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Известувања"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерија"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Слики од екранот"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Општи пораки"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Инстант апликации"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Поставување"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Капацитет"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Совети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Инстант апликации"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локација"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"снимање на екранот"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Подготвеност"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да ја емитувате сесијава, отворете ја апликацијата."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Сопри со емитување"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Достапни уреди за аудиоизлез."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционира емитувањето"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитување"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Луѓето во ваша близина со компатибилни уреди со Bluetooth може да ги слушаат аудиозаписите што ги емитувате"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Од <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Отфрли го копираниот текст"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отфрли го корисничкиот интерфејс за копирање"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменете го копираниот текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменете ја копираната слика"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Испратете до уред во близина"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонот се исклучени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известување}one{# известување}other{# известувања}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитување"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се прекине емитувањето на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитувате на <xliff:g id="SWITCHAPP">%1$s</xliff:g> или го промените излезот, тековното емитување ќе запре"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитување на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Променете излез"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 78be6dda9184..96c8a49ae0b6 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Исклучен"</item>
<item msgid="460891964396502657">"Вклучен"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недостапно"</item>
+ <item msgid="8014986104355098744">"Исклучено"</item>
+ <item msgid="5966994759929723339">"Вклучено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index f9732ca39ef3..4ca39867bd95 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"സ്ഥിരീകരിച്ചു"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"പൂർത്തിയാക്കാൻ സ്ഥിരീകരിക്കുക ടാപ്പ് ചെയ്യൂ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുടരാൻ അമർത്തുക."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അമർത്തുക."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"പിൻ ഉപയോഗിക്കുക"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"പാറ്റേൺ ഉപയോഗിക്കുക"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"സ്‌ക്രീൻ സ്വയമേവ തിരിയൽ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"സ്‌ക്രീൻ സ്വയമേവ തിരിക്കുക"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"സ്ക്രീൻ സേവർ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ക്യാമറ ആക്‌സസ്"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"മൈക്ക് ആക്‌സസ്"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ലഭ്യമാണ്"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"തുറക്കാൻ മുകളിലോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"തുറക്കാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുറക്കാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുറക്കാൻ അമർത്തുക."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"മുഖം തിരിച്ചറിഞ്ഞു. തുറക്കാൻ അമർത്തുക."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"മുഖം തിരിച്ചറിഞ്ഞു. തുറക്കാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ഇടത്തേക്ക് നീക്കുക"</item>
<item msgid="5558598599408514296">"താഴേക്ക് നീക്കുക"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"അതെ, തുടരുക"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"അതിഥി മോഡ്"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"നിങ്ങൾ അതിഥി മോഡിലാണ്"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"പുതിയൊരു ഉപയോക്താവിനെ ചേർത്താൽ അതിഥി മോഡിൽ നിന്ന് പുറത്ത് കടക്കുകയും നിലവിലെ അതിഥി മോഡിലുള്ള എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കുകയും ചെയ്യും."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ഉപയോക്തൃ പരിധി എത്തി"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">നിങ്ങൾക്ക് <xliff:g id="COUNT">%d</xliff:g> ഉപയോക്താക്കളെ വരെ ചേർക്കാനാവും.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"മുന്നറിയിപ്പുകൾ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ബാറ്ററി"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"സ്‌ക്രീൻഷോട്ടുകൾ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"പൊതുവായ സന്ദേശങ്ങൾ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"സജ്ജീകരണം"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"സ്റ്റോറേജ്"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"സൂചനകൾ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ക്യാമറ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ലൊക്കേഷന്‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"മൈക്രോഫോൺ"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"സ്ക്രീൻ റെക്കോർഡിംഗ്"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ഈ സെഷൻ കാസ്റ്റ് ചെയ്യാൻ, ആപ്പ് തുറക്കുക."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"അജ്ഞാതമായ ആപ്പ്"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ഓഡിയോ ഔട്ട്‌പുട്ടിന് ലഭ്യമായ ഉപകരണങ്ങൾ."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്‌കാസ്‌റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ബ്രോഡ്‌കാസ്റ്റ്"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"അനുയോജ്യമായ Bluetooth ഉപകരണങ്ങളോടെ സമീപമുള്ള ആളുകൾക്ക് നിങ്ങൾ ബ്രോഡ്‌കാസ്‌റ്റ് ചെയ്യുന്ന മീഡിയ കേൾക്കാനാകും"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"പൂർത്തിയായി"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"പകർത്തി"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിൽ നിന്ന്"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"പകർത്തിയ ടെക്സ്റ്റ് ഡിസ്‌മിസ് ചെയ്യുക"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"പകർപ്പ് UI ഡിസ്‌മിസ് ചെയ്യുക"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"പകർത്തിയ ടെക്സ്റ്റ് എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"പകർത്തിയ ചിത്രം എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"സമീപത്തുള്ള ഉപകരണത്തിലേക്ക് അയയ്ക്കുക"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ക്യാമറയും മൈക്കും ഓഫാണ്"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"പ്രക്ഷേപണം ചെയ്യുന്നു"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്‌കാസ്റ്റ് അവസാനിക്കും"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുക"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ഔട്ട്പുട്ട് മാറ്റുക"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"അജ്ഞാതം"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index 12089288d134..7a078737aa96 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ഓഫാണ്"</item>
<item msgid="460891964396502657">"ഓണാണ്"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ലഭ്യമല്ല"</item>
+ <item msgid="8014986104355098744">"ഓഫാണ്"</item>
+ <item msgid="5966994759929723339">"ഓണാണ്"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0e6a9a163135..8126103064a3 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Баталгаажсан"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Дуусгахын тулд баталгаажуулахыг товших"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд түгжээг тайлах дүрс тэмдэг дээр дараарай."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Царайг таньсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Царайг таньсан. Үргэлжлүүлэх бол түгжээг тайлах дүрсийг дар."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Баталгаажуулагдсан"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ПИН ашиглах"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Хээ ашиглах"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Дэлгэц амраагч"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Камерын хандалт"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофоны хандалт"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Боломжтой"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Нээхийн тулд дээш шударна уу"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Нээхийн тулд түгжээг тайлах дүрс тэмдэг дээр дараарай"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Царайгаар түгжээг тайлсан. Нээхийн тулд түгжээг тайлах дүрс тэмдэг дээр дараарай."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Царайгаар түгжээг тайлсан. Нээхийн тулд дарна уу."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Царайг таньсан. Нээхийн тулд дарна уу."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Царайг таньсан. Нээх бол түгжээг тайлах дүрсийг дарна уу."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Зүүн тийш зөөх"</item>
<item msgid="5558598599408514296">"Доош зөөх"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Тийм, үргэлжлүүлэх"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Зочны горим"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Та зочны горимд байна"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Шинэ хэрэглэгч нэмснээр зочны горимоос гаргах бөгөөд бүх апп болон өгөгдлийг одоогийн зочны харилцан үйлдлээс устгана."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Хэрэглэгчийн хязгаарт хүрсэн"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Та <xliff:g id="COUNT">%d</xliff:g> хүртэлх хэрэглэгч нэмэх боломжтой.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сэрэмжлүүлэг"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарей"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Дэлгэцийн зураг дарах"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн мессеж"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Шуурхай апп"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Тохируулга"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Хадгалах сан"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Заавар"</string>
<string name="instant_apps" msgid="8337185853050247304">"Шуурхай апп"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камер"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"байршил"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"дэлгэцийн бичлэг"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Энэ үйл явдлыг дамжуулахын тулд аппыг нээнэ үү."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Үл мэдэгдэх апп"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Дамжуулахыг зогсоох"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио гаралт хийх боломжтой төхөөрөмжүүд."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Нэвтрүүлэлт"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Тохиромжтой Bluetooth төхөөрөмжүүдтэй таны ойролцоох хүмүүс таны нэвтрүүлж буй медиаг сонсох боломжтой"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Болсон"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Хууллаа"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-с"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Хуулсан текстийг үл хэрэгсэх"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Хуулах UI-г хаах"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Хуулсан текстийг засах"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Хуулсан зургийг засах"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ойролцоох төхөөрөмж рүү илгээх"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камер болон микрофон унтраалттай байна"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Нэвтрүүлэлт"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлэх"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Гаралтыг өөрчлөх"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Тодорхойгүй"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index 3748440058b6..776c4877d1ad 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Унтраалттай"</item>
<item msgid="460891964396502657">"Асаалттай"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Боломжгүй"</item>
+ <item msgid="8014986104355098744">"Унтраалттай"</item>
+ <item msgid="5966994759929723339">"Асаалттай"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 7e9629d09462..1c5594385fb3 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"चेहऱ्याने अनलॉक केले. सुरू ठेवण्यासाठी अनलॉक करा आयकन दाबा."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन दाबा."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ऑथेंटिकेशन केलेले"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन वापरा"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पॅटर्न वापरा"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रीन सेव्हर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"कॅमेराचा अ‍ॅक्सेस"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइकचा ॲक्सेस"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध आहे"</string>
@@ -307,12 +311,15 @@
<string name="zen_alarms_introduction" msgid="3987266042682300470">"अलार्म व्यतिरिक्त तुम्हाला कोणत्याही आवाज आणि कंपनांचा व्यत्त्यय आणला जाणार नाही. तरीही तुम्ही प्ले करायचे ठरवलेले कोणतेही संगीत, व्हिडिओ आणि गेमचे आवाज ऐकू शकतात."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"सानुकूलित करा"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"हे अलार्म, संगीत, व्हिडिओ आणि गेमसह, सर्व आवाज आणि कंपने ब्लॉक करते. तरीही तुम्ही फोन कॉल करू शकतात."</string>
- <string name="zen_silence_introduction" msgid="6117517737057344014">"हे अलार्म, संगीत, व्हिडिओ आणि गेम यांसह, सर्व आवाज आणि व्हायब्रेशन ब्लॉक करते."</string>
+ <string name="zen_silence_introduction" msgid="6117517737057344014">"हे अलार्म, संगीत, व्हिडिओ आणि गेम यासह, सर्व आवाज आणि कंपने अवरोधित करते."</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="9140109453735019209">"उघडण्यासाठी अनलॉक करा आयकन दाबा"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहऱ्याने अनलॉक केले. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी दाबा."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी दाबा."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"डावीकडे हलवा"</item>
<item msgid="5558598599408514296">"खाली हलवा"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरू ठेवा"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"अतिथी मोड"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"तुम्ही अतिथी मोडमध्ये आहात"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"नवीन वापरकर्ता जोडल्याने अतिथी मोडमधून बाहेर पडाल आणि सध्याच्या अतिथी सत्रातील सर्व अ‍ॅप्स व डेटा हटवला जाईल."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"वापरकर्ता मर्यादा गाठली"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यांपर्यंत जोडू शकता.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सूचना"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"बॅटरी"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रीनशॉट"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सर्वसाधारण मेसेज"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"सेटअप"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"सूचना"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<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="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रीन रेकॉर्डिंग"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"हे सेशन कास्ट करण्यासाठी, कृपया ॲप उघडा."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात अ‍ॅप"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करणे थांबवा"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडिओ आउटपुटसाठी उपलब्ध डिव्हाइस."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करा"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कंपॅटिबिल ब्लूटूथ डिव्‍हाइस असलेले तुमच्या जवळपासचे लोक हे तुम्ही ब्रॉडकास्ट करत असलेला मीडिया ऐकू शकतात"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"पूर्ण झाले"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी केले"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> वरून"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कॉपी केलेला मजकूर डिसमिस करा"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी केलेले UI डिसमिस करा"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी केलेला मजकूर संपादित करा"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी केलेली इमेज संपादित करा"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"जवळपासच्या डिव्हाइसवर पाठवा"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कॅमेरा आणि माइक बंद आहेत"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट करत आहे"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण करा"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपूट बदला"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"अज्ञात"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index a6a3873f95d7..f75f0d097998 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"बंद आहे"</item>
<item msgid="460891964396502657">"सुरू आहे"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"उपलब्ध नाही"</item>
+ <item msgid="8014986104355098744">"बंद आहे"</item>
+ <item msgid="5966994759929723339">"सुरू आहे"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 47d8a849188c..c78caba8e566 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Disahkan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketik Sahkan untuk menyelesaikan"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Dibuka kunci dengan wajah. Tekan ikon buka kunci untuk teruskan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Dibuka kunci dengan wajah. Tekan untuk meneruskan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dicam. Tekan untuk meneruskan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dicam. Tekan ikon buka kunci untuk meneruskan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Disahkan"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan corak"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Penyelamat skrin"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Leret ke atas untuk buka"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Tekan ikon buka kunci untuk buka"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Dibuka kunci dengan wajah. Tekan ikon buka kunci untuk buka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Dibuka kunci dengan wajah. Tekan untuk membuka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Wajah dicam. Tekan untuk membuka."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Wajah dicam. Tekan ikon buka kunci untuk membuka."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Alih ke kiri"</item>
<item msgid="5558598599408514296">"Alih ke bawah"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, teruskan"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mod tetamu"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Anda dalam mod tetamu"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Tindakan menambahkan pengguna baharu akan menyebabkan anda keluar daripada mod tetamu dan memadamkan semua apl dan data daripada sesi tetamu semasa."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Had pengguna dicapai"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Anda boleh menambah sehingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Makluman"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Tangkapan skrin"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesej Am"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Apl Segera"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Persediaan"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storan"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Pembayang"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apl Segera"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"rakaman skrin"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Untuk menghantar sesi ini, sila buka apl."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Apl yang tidak diketahui"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Berhenti menghantar"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Peranti tersedia untuk audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara siaran berfungsi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siarkan"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang berdekatan anda dengan peranti Bluetooth yang serasi boleh mendengar media yang sedang anda siarkan"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Selesai"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Daripada <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ketepikan teks yang disalin"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ketepikan penyalinan UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit imej yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Hantar ke peranti berdekatan"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon dimatikan"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pemberitahuan}other{# pemberitahuan}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Tukar output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tidak diketahui"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index cfd831a1d94b..9fa7ab51d064 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Mati"</item>
<item msgid="460891964396502657">"Hidup"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Tidak tersedia"</item>
+ <item msgid="8014986104355098744">"Mati"</item>
+ <item msgid="5966994759929723339">"Hidup"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index dc8b82e66dc1..008bbb0a1ce1 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"အတည်ပြုပြီးပြီ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"အပြီးသတ်ရန်အတွက် \'အတည်ပြုရန်\' ကို တို့ပါ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ရှေ့ဆက်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ပင်နံပါတ်သုံးရန်"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ပုံစံကို သုံးရန်"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"အော်တို-လည်"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"မျက်နှာပြင်အား အလိုအလျောက်လှည့်ခြင်း"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"စကရင်ချွေတာစနစ်"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ကင်မရာသုံးခွင့်"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"မိုက်သုံးခွင့်"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ရနိုင်သည်"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ဖွင့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ဖွင့်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ဖွင့်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ဖွင့်ရန် နှိပ်ပါ။"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"မျက်နှာ မှတ်မိသည်။ ဖွင့်ရန် နှိပ်ပါ။"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"မျက်နှာ မှတ်မိသည်။ ဖွင့်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ဘယ်ဘက်သို့ရွှေ့ရန်"</item>
<item msgid="5558598599408514296">"အောက်သို့ရွှေ့ရန်"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ပြန်စပါ"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ဆက်လုပ်ပါ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ဧည့်သည်မုဒ်"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"သင်သည် ဧည့်သည်မုဒ်တွင် ဖြစ်သည်"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"အသုံးပြုသူ အသစ်ထည့်ခြင်းက ဧည့်သည်မုဒ်မှ ထွက်သွားမည်ဖြစ်ပြီး လက်ရှိဧည့်သည် စက်ရှင်မှ အက်ပ်နှင့် ဒေတာအားလုံးကို ဖျက်လိုက်ပါမည်။"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"အသုံးပြုသူ အကန့်အသတ် ပြည့်သွားပါပြီ"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">အသုံးပြုသူ <xliff:g id="COUNT">%d</xliff:g> ဦးအထိ ထည့်နိုင်သည်။</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"သတိပေးချက်များ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ဘက်ထရီ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"မျက်နှာပြင်ဓာတ်ပုံများ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"အထွေထွေ မက်ဆေ့ဂျ်များ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"စနစ်ထည့်ရန်"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"သိုလှောင်ခန်း"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"အရိပ်အမြွက်များ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ကင်မရာ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"တည်နေရာ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"မိုက်ခရိုဖုန်း"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"စခရင်ရိုက်ကူးမှု"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"အက်ပ်ဖွင့်ပြီး ဤစက်ရှင်ကို ကာစ်လုပ်နိုင်သည်။"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"အမည်မသိ အက်ပ်"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ကာစ် ရပ်ရန်"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"အသံအထွက်အတွက် ရရှိနိုင်သောစက်များ။"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ထုတ်လွှင့်ခြင်း"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"အနီးရှိတွဲသုံးနိုင်သော ဘလူးတုသ်သုံးစက် အသုံးပြုသူများက သင်ထုတ်လွှင့်နေသော မီဒီယာကို နားဆင်နိုင်သည်"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ပြီးပြီ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ကူးပြီးပါပြီ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ထံမှ"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"မိတ္တူကူးထားသောစာသားကို ပယ်ရန်"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI မိတ္တူမကူးတော့ရန်"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ကူးထားသည့်စာသားကို တည်းဖြတ်ရန်"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ကူးထားသည့်ပုံကို ပြင်ဆင်ရန်"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"အနီးတစ်ဝိုက်ရှိ စက်များသို့ ပို့ရန်"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"နိုးစက် သတ်မှတ်ထားသည်"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ကင်မရာနှင့် မိုက် ပိတ်ထားသည်"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ထုတ်လွှင့်ခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ထုတ်လွှင့်ခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"အထွက်ကို ပြောင်းခြင်း"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"မသိ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 665af20761c7..493a7f0977c6 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ပိတ်"</item>
<item msgid="460891964396502657">"ဖွင့်"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"မရနိုင်ပါ"</item>
+ <item msgid="8014986104355098744">"ပိတ်"</item>
+ <item msgid="5966994759929723339">"ဖွင့်"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f81e846673fa..f2119f3b7a96 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekreftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trykk på Bekreft for å fullføre"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Låst opp med ansiktet. Trykk på lås opp-ikon for å fortsette"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst opp med ansiktet. Trykk for å fortsette."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet er gjenkjent. Trykk for å fortsette."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentisert"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Bruk PIN-kode"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Bruk mønster"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skjermsparer"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratilgang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofontilgang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgjengelig"</string>
@@ -313,12 +317,13 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Sveip opp for å åpne"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Trykk på lås opp-ikonet for å åpne"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Låst opp med ansiktet. Trykk på lås opp-ikon for å fortsette"</string>
- <string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Flytt til venstre"</item>
- <item msgid="5558598599408514296">"Flytt ned"</item>
- <item msgid="4844142668312841831">"Flytt til høyre"</item>
- <item msgid="5640521437931460125">"Flytt opp"</item>
- </string-array>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Låst opp med ansiktet. Trykk for å åpne."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansiktet er gjenkjent. Trykk for å åpne."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Sveip opp for å prøve igjen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
@@ -345,6 +350,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsett"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gjestemodus"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Du er i gjestemodus"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Hvis du legger til en ny bruker, avsluttes gjestemodus, og alle apper og data fra den gjeldende gjesteøkten slettes."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Grensen for antall brukere er nådd"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Du kan legge til opptil <xliff:g id="COUNT">%d</xliff:g> brukere.</item>
@@ -691,7 +699,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Varsler"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skjermdumper"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Generelle meldinger"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hint"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posisjon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"skjermopptak"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"For å caste denne økten, åpne appen."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukjent app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stopp castingen"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tilgjengelige enheter for lydutgang."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Kringkasting"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Folk i nærheten med kompatible Bluetooth-enheter kan lytte til mediene du kringkaster"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Ferdig"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Lukk kopiert tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Lukk kopi-UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger den kopierte teksten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger det kopierte bildet"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til en enhet i nærheten"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er av"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Kringkaster"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Kringkast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Endre utgang"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukjent"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index a28b817b765b..6fa902a662ff 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Utilgjengelig"</item>
+ <item msgid="8014986104355098744">"Av"</item>
+ <item msgid="5966994759929723339">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index a55abcbb6156..01d53f2b14e7 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि भयो"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूरा गर्नका लागि पुष्टि गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न अनलक आइकनमा थिच्नुहोस्।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न थिच्नुहोस्।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"अनुहार पहिचान गरियो। जारी राख्न थिच्नुहोस्।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"अनुहार पहिचान गरियो। जारी राख्न अनलक आइकनमा थिच्नुहोस्।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"प्रमाणीकरण गरियो"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN प्रयोग गर्नुहोस्"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ढाँचा प्रयोग गर्नुहोस्"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रिन सेभर"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"क्यामेरा प्रयोग गर्ने अनुमति"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक प्रयोग गर्ने अनुमति"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध छ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"खोल्न अनलक आइकनमा थिच्नुहोस्"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"अनुहार प्रयोग गरी अनलक गरियो। खोल्न अनलक आइकनमा थिच्नुहोस्।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"अनुहार प्रयोग गरी अनलक गरियो। डिभाइस खोल्न थिच्नुहोस्।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"अनुहार पहिचान गरियो। डिभाइस खोल्न थिच्नुहोस्।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"अनुहार पहिचान गरियो। डिभाइस खोल्न अनलक आइकनमा थिच्नुहोस्।"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"बायाँ सार्नुहोस्"</item>
<item msgid="5558598599408514296">"तल सार्नुहोस्"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हो, जारी राख्नुहोस्"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"अतिथि मोड"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"तपाईं अतिथि मोड चलाउँदै हुनुहुन्छ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"तपाईंले नयाँ प्रयोगकर्ता थप्नुभयो भने तपाईं अतिथि मोडबाट बाहिरिनु हुने छ र हालको अतिथि सत्रका सबै एप तथा डेटा मेटिने छ।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"प्रयोगकर्ताको सीमा पुग्यो"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">तपाईं अधिकतम <xliff:g id="COUNT">%d</xliff:g> प्रयोगहरू मात्र थप्न सक्नुहुन्छ।</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"सतर्कताहरू"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ब्याट्री"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रिनशटहरू"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"सामान्य सन्देशहरू"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"सेटअप गर्नुहोस्"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"भण्डारण"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"सङ्केतहरू"</string>
<string name="instant_apps" msgid="8337185853050247304">"तात्कालिक एपहरू"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"क्यामेरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफोन"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रिन रेकर्डिङ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"यो सत्र कास्ट गर्न चाहनुहुन्छ भने कृपया एप खोल्नुहोस्।"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात एप"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट गर्न छाड्नुहोस्"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"अडियो आउटपुटका लागि उपलब्ध डिभाइसहरू।"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"प्रसारण"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कम्प्याटिबल ब्लुटुथ डिभाइस भएका नजिकैका मान्छेहरू तपाईंले प्रसारण गरिरहनुभएको मिडिया सुन्न सक्छन्"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"सम्पन्न भयो"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कपी गरियो"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> बाट"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कपी गरिएको टेक्स्ट हटाउनुहोस्"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कपी UI खारेज गर्नुहोस्"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कपी गरिएको टेक्स्ट सम्पादन गर्नुहोस्"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कपी गरिएको फोटो सम्पादन गर्नुहोस्"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"नजिकैको डिभाइसमा पठाउनुहोस्"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"क्यामेरा र माइक अफ छन्"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"प्रसारण गरिँदै छ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुहोस्"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट परिवर्तन गर्नुहोस्"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"अज्ञात"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 80edf29f4985..17193bafd9a3 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"अफ छ"</item>
<item msgid="460891964396502657">"अन छ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"अनुपलब्ध"</item>
+ <item msgid="8014986104355098744">"अफ"</item>
+ <item msgid="5966994759929723339">"अन"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index dc2bee56373c..54c5490d9fe6 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -66,12 +66,10 @@
<!-- media output dialog-->
<color name="media_dialog_background">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
- <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
- <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
- <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
- <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
- <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
+ <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
+ <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
+ <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
+ <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ffcccccc</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index deed394ed201..f659f5fabd75 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestigd"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestigen om te voltooien"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Ontgrendeld via gezicht. Druk op het ontgrendelicoon."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontgrendeld via gezicht. Druk om door te gaan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gezicht herkend. Druk om door te gaan."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Geverifieerd"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Pincode gebruiken"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Patroon gebruiken"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Cameratoegang"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Microfoontoegang"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beschikbaar"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Druk op het ontgrendelicoon om te openen"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Ontgrendeld via gezicht. Druk op het ontgrendelicoon."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Ontgrendeld via gezicht. Druk om te openen."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gezicht herkend. Druk om te openen."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Naar links verplaatsen"</item>
<item msgid="5558598599408514296">"Omlaag verplaatsen"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, doorgaan"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gastmodus"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Je gebruikt de gastmodus"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Als je een nieuwe gebruiker toevoegt, wordt de gastmodus afgesloten en worden alle apps en gegevens van de huidige gastsessie verwijderd."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerslimiet bereikt"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Je kunt maximaal <xliff:g id="COUNT">%d</xliff:g> gebruikers toevoegen.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Meldingen"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batterij"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Screenshots"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Algemene berichten"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant-apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Instellen"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Opslag"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant-apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locatie"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfoon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"schermopname"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Als je deze sessie wilt casten, open je de app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Casten stoppen"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beschikbare apparaten voor audio-uitvoer."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Uitzending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mensen bij jou in de buurt met geschikte bluetooth-apparaten kunnen luisteren naar de media die je uitzendt"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klaar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieerd"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Uit <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Gekopieerde tekst sluiten"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI voor kopiëren sluiten"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Gekopieerde tekst bewerken"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Gekopieerde afbeelding bewerken"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Naar apparaat in de buurt sturen"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera en microfoon staan uit"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitzending"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzenden"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Uitvoer wijzigen"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Onbekend"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index c4603b22157c..fbccd78eeb8f 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Uit"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Niet beschikbaar"</item>
+ <item msgid="8014986104355098744">"Uit"</item>
+ <item msgid="5966994759929723339">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ac91856f5578..64a1b0ae4934 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ସୁନିଶ୍ଚିତ କରାଯାଇଛି"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ସୁନିଶ୍ଚିତ କରନ୍ତୁରେ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ପାଟର୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ଅଟୋ-ରୋଟେଟ୍"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ଅଟୋ-ରୋଟେଟ୍ ସ୍କ୍ରିନ୍"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ୍‍"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ସ୍କ୍ରିନ ସେଭର"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"କ୍ୟାମେରା ଆକ୍ସେସ୍"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ମାଇକ୍ ଆକ୍ସେସ୍"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ଉପଲବ୍ଧ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ଖୋଲିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ଖୋଲିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଖୋଲିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଖୋଲିବାକୁ ଦବାନ୍ତୁ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଖୋଲିବାକୁ ଦବାନ୍ତୁ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଖୋଲିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ବାମକୁ ମୁଭ କରନ୍ତୁ"</item>
<item msgid="5558598599408514296">"ତଳକୁ ମୁଭ କରନ୍ତୁ"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ହଁ, ଜାରି ରଖନ୍ତୁ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ଅତିଥି ମୋଡ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ଆପଣ ଅତିଥି ମୋଡରେ ଅଛନ୍ତି"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରିବା ଦ୍ୱାରା ଅତିଥି ମୋଡରୁ ବାହାରି ଯିବ ଏବଂ ବର୍ତ୍ତମାନର ଅତିଥି ସେସନରୁ ସମସ୍ତ ଆପ ଓ ଡାଟା ଡିଲିଟ ହୋଇଯିବ।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ଉପଯୋଗକର୍ତ୍ତା ସୀମାରେ ପହଞ୍ଚିଛି"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">କେବଳ <xliff:g id="COUNT">%d</xliff:g> ଉପଯୋଗକର୍ତ୍ତା ହିଁ ତିଆରି କରିହେବ।</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ଆଲର୍ଟଗୁଡ଼ିକ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ବ୍ୟାଟେରୀ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ସ୍କ୍ରୀନଶଟ୍‍"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ସାଧାରଣ ମେସେଜ୍"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ସେଟଅପ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ଷ୍ଟୋରେଜ୍‌"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ହିଣ୍ଟ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"କ୍ୟାମେରା"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ଲୋକେସନ୍‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ମାଇକ୍ରୋଫୋନ୍"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ସ୍କ୍ରିନ ରେକର୍ଡିଂ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ଏହି ସେସନକୁ କାଷ୍ଟ କରିବା ପାଇଁ, ଦୟାକରି ଆପ ଖୋଲନ୍ତୁ।"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ଅଜଣା ଆପ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"କାଷ୍ଟ କରିବା ବନ୍ଦ କରନ୍ତୁ"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ଅଡିଓ ଆଉଟପୁଟ ପାଇଁ ଉପଲବ୍ଧ ଡିଭାଇସଗୁଡ଼ିକ।"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ବ୍ରଡକାଷ୍ଟ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ଆପଣଙ୍କ ଆଖପାଖର କମ୍ପାଟିବଲ ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଥିବା ଲୋକମାନେ ଆପଣ ବ୍ରଡକାଷ୍ଟ କରୁଥିବା ମିଡିଆ ଶୁଣିପାରିବେ"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ହୋଇଗଲା"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"କପି କରାଯାଇଛି"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ରୁ"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଖାରଜ କରନ୍ତୁ"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"କପି କରାଯାଇଥିବା UIକୁ ଖାରଜ କରନ୍ତୁ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"କପି କରାଯାଇଥିବା ଇମେଜକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ନିକଟସ୍ଥ ଡିଭାଇସକୁ ପଠାନ୍ତୁ"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"କ୍ୟାମେରା ଏବଂ ମାଇକ ବନ୍ଦ ଅଛି"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ବ୍ରଡକାଷ୍ଟ କରୁଛି"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ଆଉଟପୁଟ ବଦଳାନ୍ତୁ"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ଅଜଣା"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 2d9fb84790cd..acaa3fb6f6a8 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ବନ୍ଦ ଅଛି"</item>
<item msgid="460891964396502657">"ଚାଲୁ ଅଛି"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ଉପଲବ୍ଧ ନାହିଁ"</item>
+ <item msgid="8014986104355098744">"ବନ୍ଦ ଅଛି"</item>
+ <item msgid="5966994759929723339">"ଚାଲୁ ଅଛି"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9e605d927e2e..7b41da317837 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ਪੁਸ਼ਟੀ ਕੀਤੀ ਗਈ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ਪੂਰਾ ਕਰਨ ਲਈ ਪੁਸ਼ਟੀ ਕਰੋ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ਪਿੰਨ ਵਰਤੋ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ਪੈਟਰਨ ਵਰਤੋ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ਕੈਮਰਾ ਪਹੁੰਚ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ਮਾਈਕ ਪਹੁੰਚ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ਉਪਲਬਧ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"ਖੋਲ੍ਹਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"ਖੋਲ੍ਹਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਖੋਲ੍ਹਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ।"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਖੋਲ੍ਹਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ਖੱਬੇ ਲਿਜਾਓ"</item>
<item msgid="5558598599408514296">"ਹੇਠਾਂ ਲਿਜਾਓ"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ਹਾਂ, ਜਾਰੀ ਰੱਖੋ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ਮਹਿਮਾਨ ਮੋਡ"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ਤੁਸੀਂ ਮਹਿਮਾਨ ਮੋਡ ਵਿੱਚ ਹੋ"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਨਾਲ ਮੌਜੂਦਾ ਮਹਿਮਾਨ ਮੋਡ ਚਲਾ ਜਾਵੇਗਾ ਅਤੇ ਮੌਜੂਦਾ ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਦੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ਸੁਚੇਤਨਾਵਾਂ"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"ਬੈਟਰੀ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ਆਮ ਸੁਨੇਹੇ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ਸੈੱਟਅੱਪ ਕਰੋ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ਸਟੋਰੇਜ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ਸੰਕੇਤ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ਕੈਮਰਾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ਟਿਕਾਣਾ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ਇਸ ਸੈਸ਼ਨ ਨੂੰ ਕਾਸਟ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਐਪ ਖੋਲ੍ਹੋ।"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ਅਗਿਆਤ ਐਪ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ਆਡੀਓ ਆਊਟਪੁੱਟ ਲਈ ਉਪਲਬਧ ਡੀਵਾਈਸ।"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ਪ੍ਰਸਾਰਨ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ਅਨੁਰੂਪ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਨਾਲ ਨਜ਼ਦੀਕੀ ਲੋਕ ਤੁਹਾਡੇ ਵੱਲੋਂ ਪ੍ਰਸਾਰਨ ਕੀਤੇ ਜਾ ਰਹੇ ਮੀਡੀਆ ਨੂੰ ਸੁਣ ਸਕਦੇ ਹਨ"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ਹੋ ਗਿਆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ਕਾਪੀ ਕੀਤੀ ਗਈ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ਤੋਂ"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ਕਾਪੀ ਕੀਤੇ UI ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ਕਾਪੀ ਕੀਤੇ ਗਏ ਚਿੱਤਰ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ \'ਤੇ ਭੇਜੋ"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ ਬੰਦ ਹਨ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ਪ੍ਰਸਾਰਨ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰੋ"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ਆਊਟਪੁੱਟ ਬਦਲੋ"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ਅਗਿਆਤ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index 737b2b60ac60..9653b923224a 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ਬੰਦ"</item>
<item msgid="460891964396502657">"ਚਾਲੂ"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ਉਪਲਬਧ ਨਹੀਂ"</item>
+ <item msgid="8014986104355098744">"ਬੰਦ"</item>
+ <item msgid="5966994759929723339">"ਚਾਲੂ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index db9b805ccefe..92d555ddba02 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potwierdzono"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Aby zakończyć, kliknij Potwierdź"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Odblokowano skanem twarzy. Aby kontynuować, kliknij ikonę odblokowywania."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odblokowano rozpoznawaniem twarzy. Kliknij, aby kontynuować."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Twarz rozpoznana. Kliknij, aby kontynuować."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Twarz rozpoznana. Aby kontynuować, kliknij ikonę odblokowywania."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Uwierzytelniono"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Użyj kodu PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Użyj wzoru"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Wygaszacz ekranu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostęp do aparatu"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostęp do mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Odblokowany"</string>
@@ -317,12 +321,13 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Przesuń w górę, by otworzyć"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Aby otworzyć, kliknij ikonę odblokowywania"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Odblokowano skanem twarzy. Aby otworzyć, kliknij ikonę odblokowywania."</string>
- <string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Przenieś w lewo"</item>
- <item msgid="5558598599408514296">"Przenieś w dół"</item>
- <item msgid="4844142668312841831">"Przenieś w prawo"</item>
- <item msgid="5640521437931460125">"Przenieś w górę"</item>
- </string-array>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odblokowano rozpoznawaniem twarzy. Naciśnij, by otworzyć."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Twarz rozpoznana. Naciśnij, by otworzyć."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Twarz rozpoznana. Aby otworzyć, kliknij ikonę odblokowywania."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Przesuń w górę, by spróbować ponownie"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
@@ -349,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Tak, kontynuuj"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Tryb gościa"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Jesteś w trybie gościa"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dodanie nowego użytkownika spowoduje zamknięcie trybu gościa. Wszystkie aplikacje i dane z obecnej sesji gościa zostaną usunięte."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Osiągnięto limit użytkowników"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="few">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkowników.</item>
@@ -701,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerty"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Zrzuty ekranu"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Wiadomości"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć wewnętrzna"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wskazówki"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacje błyskawiczne"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"aparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokalizacja"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"nagrywanie ekranu"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Aby przesłać tę sesję, otwórz aplikację."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nieznana aplikacja"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zatrzymaj przesyłanie"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostępne urządzenia do odtwarzania dźwięku."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisja"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osoby w pobliżu ze zgodnymi urządzeniami Bluetooth mogą słuchać transmitowanych przez Ciebie multimediów"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotowe"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopiowano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odrzuć skopiowany tekst"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zamknij UI kopiowania"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edytuj skopiowany tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edytuj skopiowany obraz"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Wyślij na urządzenie w pobliżu"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Aparat i mikrofon są wyłączone"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmisja"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmisja aplikacji <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmień dane wyjściowe"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Brak informacji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index c1a4059f6393..50650986c517 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Wyłączony"</item>
<item msgid="460891964396502657">"Włączony"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Brak dostępu"</item>
+ <item msgid="8014986104355098744">"Wyłączono"</item>
+ <item msgid="5966994759929723339">"Włączono"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 9930250cb3bb..5db6545b66ee 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Desbloqueado pelo rosto. Pressione o ícone de desbloqueio para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pressione o ícone de desbloqueio para abrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Desbloqueado pelo rosto. Pressione o ícone de desbloqueio para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado pelo rosto. Pressione para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Pressione para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Pressione o ícone de desbloq. para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mais para a esquerda"</item>
<item msgid="5558598599408514296">"Mais para baixo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo visitante"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de tela"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de tela"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para saída de áudio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dispensar texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index abf8749e84d7..bc7efe6a8682 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0a01592f3297..a7cee46ae36d 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em Confirmar para concluir."</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Desbloqueado c/ rosto. Prima o ícone de desb. p/ continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado com o rosto. Prima para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Prima para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Prima ícone de desbloqueio para continuar"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilizar padrão"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Proteção de ecrã"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso câmara"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ac. microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize rapidamente para cima para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Prima o ícone de desbloqueio para abrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Desbloqueado com o rosto. Prima o ícone de desbl. p/ abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado com o rosto. Prima para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Prima para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Prima o ícone de desbloqueio para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mover para a esquerda"</item>
<item msgid="5558598599408514296">"Mover para baixo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo convidado"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Está no modo convidado"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo utilizador, o modo convidado é fechado e todas as apps e dados da sessão de convidado atual são eliminados."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de ecrã"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Apps instantâneas"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuração"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugestões"</string>
<string name="instant_apps" msgid="8337185853050247304">"Apps instantâneas"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de ecrã"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sessão, abra a app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecida"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para a saída de áudio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmissão"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas de si com dispositivos Bluetooth compatíveis podem ouvir o conteúdo multimédia que está a transmitir"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluir"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Da app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorar texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar cópia de IU"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}other{# notificações}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmita a app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Altere a saída"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecida"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index c8e557b38f9b..0a0102032c6a 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9930250cb3bb..5db6545b66ee 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Desbloqueado pelo rosto. Pressione o ícone de desbloqueio para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pressione o ícone de desbloqueio para abrir"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Desbloqueado pelo rosto. Pressione o ícone de desbloqueio para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Desbloqueado pelo rosto. Pressione para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Rosto reconhecido. Pressione para abrir."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Rosto reconhecido. Pressione o ícone de desbloq. para abrir."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Mais para a esquerda"</item>
<item msgid="5558598599408514296">"Mais para baixo"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modo visitante"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertas"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturas de tela"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mensagens gerais"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de tela"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para saída de áudio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dispensar texto copiado"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index abf8749e84d7..bc7efe6a8682 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponível"</item>
+ <item msgid="8014986104355098744">"Desativado"</item>
+ <item msgid="5966994759929723339">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ce01a563c16d..f4454a98837a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atingeți Confirmați pentru a finaliza"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"S-a deblocat cu ajutorul feței. Apăsați pictograma de deblocare pentru a continua"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S-a deblocat cu ajutorul feței. Apăsați pentru a continua."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Chipul a fost recunoscut. Apăsați pentru a continua."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apăsați pictograma de deblocare să continuați."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificat"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Folosiți PIN-ul"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Folosiți modelul"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screensaver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acces la cameră"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Acces la microfon"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibil"</string>
@@ -315,6 +319,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Glisați în sus pentru a deschide"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Apăsați pictograma de deblocare pentru a deschide"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"S-a deblocat cu ajutorul feței. Apăsați pictograma de deblocare pentru a deschide"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"S-a deblocat cu ajutorul feței. Apăsați pentru a deschide."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Chipul a fost recunoscut. Apăsați pentru a deschide."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Chip recunoscut. Apăsați pictograma de deblocare pentru a deschide"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Deplasați spre stânga"</item>
<item msgid="5558598599408514296">"Deplasați în jos"</item>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, continuați"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modul pentru invitați"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Folosiți modul pentru invitați"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dacă adăugați un utilizator nou, veți ieși din modul pentru invitați și se vor șterge toate aplicațiile și datele din sesiunea pentru invitați actuală."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Ați atins limita de utilizatori"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="few">Puteți adăuga maximum <xliff:g id="COUNT">%d</xliff:g> utilizatori.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerte"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Capturi de ecran"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesaje generale"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplicații instantanee"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurarea"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Stocare"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Indicii"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicații instantanee"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cameră foto"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locație"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"înregistrare de ecran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pentru a proiecta această sesiune, deschideți aplicația."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicație necunoscută"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiectați"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispozitive disponibile pentru ieșire audio."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmiteți"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Persoanele din apropiere cu dispozitive Bluetooth compatibile pot asculta conținutul pe care îl transmiteți"</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gata"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S-a copiat"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Din <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Închideți textul copiat"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Închideți copierea interfeței de utilizare"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editați textul copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editați imaginea copiată"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Trimiteți către un dispozitiv din apropiere"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera și microfonul sunt dezactivate"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Se difuzează"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Opriți difuzarea <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbați rezultatul, difuzarea actuală se va opri"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Schimbați rezultatul"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Necunoscută"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index 1ad0a75f39ba..7b7bb3ac11d8 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Dezactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Indisponibil"</item>
+ <item msgid="8014986104355098744">"Dezactivat"</item>
+ <item msgid="5966994759929723339">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c02195933f23..8d241aba777b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Подтверждено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Нажмите \"Подтвердить\""</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Сканирование выполнено. Нажмите на значок разблокировки."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблокировано сканированием лица. Нажмите, чтобы продолжить."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицо распознано. Нажмите, чтобы продолжить."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицо распознано. Нажмите на значок разблокировки."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификация выполнена"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Использовать графический ключ"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ к камере"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ к микрофону"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведите вверх, чтобы открыть"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Нажмите на значок разблокировки."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Сканирование выполнено. Нажмите на значок разблокировки."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Разблокировано сканированием лица. Нажмите, чтобы открыть."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лицо распознано. Нажмите, чтобы открыть."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лицо распознано. Нажмите на значок разблокировки."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Переместите палец влево"</item>
<item msgid="5558598599408514296">"Переместите палец вниз"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжить"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Гостевой режим"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Включен гостевой режим"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Добавив нового пользователя, вы выйдете из гостевого режима. Все приложения и данные в текущем гостевом сеансе будут удалены."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут лимит"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователя.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Оповещения"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарея"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Скриншоты"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Сообщения"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Приложения с мгновенным запуском"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Настройка"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Подсказки"</string>
<string name="instant_apps" msgid="8337185853050247304">"Приложения с мгновенным запуском"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местоположение"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"запись экрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Чтобы начать трансляцию сеанса, откройте приложение"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестное приложение"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Остановить трансляцию"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступные устройства для вывода звука."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работают трансляции"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляция"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Находящиеся рядом с вами люди с совместимыми устройствами Bluetooth могут слушать медиафайлы, которые вы транслируете."</string>
@@ -925,7 +931,7 @@
<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="tap_a_network_to_connect" msgid="1565073330852369558">"Чтобы подключиться к сети, нажмите на ее название"</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>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопировано."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Из приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Удалить скопированный текст"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыть меню копирования"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменить скопированный текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменить скопированное изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Отправить на устройство поблизости"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон отключены"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# уведомление}one{# уведомление}few{# уведомления}many{# уведомлений}other{# уведомления}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляция"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Остановить трансляцию \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Если вы начнете транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" или смените целевое устройство, текущая трансляция прервется."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Транслировать на другое устройство"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Неизвестно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index e1ee39fd79ee..6255bd8ee26d 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Отключен"</item>
<item msgid="460891964396502657">"Включен"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Отключено"</item>
+ <item msgid="5966994759929723339">"Включено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 9c60ae49532f..6f72f9afa356 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"තහවුරු කළා"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"සම්පූර්ණ කිරීමට තහවුරු කරන්න තට්ටු කර."</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"මුහුණ මගින් අගුලු හරින ලදි. දිගටම කරගෙන යාමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"මුහුණ මගින් අගුලු හරින ලදි. ඉදිරියට යාමට ඔබන්න."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට ඔබන්න."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"සත්‍යාපනය විය"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN භාවිත කරන්න"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"රටාව භාවිත කරන්න"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්‍රීය කරකැවීම"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"තිර සුරැකුම"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"කැමරා ප්‍රවේශය"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"මයික් ප්‍රවේශය"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"තිබේ"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"විවෘත කිරීමට ස්වයිප් කරන්න"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"විවෘත කිරීමට අගුලු හැරීමේ නිරූපකය ඔබන්න"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"මුහුණ මගින් අගුලු හරින ලදි. විවෘත කිරීමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"මුහුණ මගින් අගුලු හරින ලදි. විවෘත කිරීමට ඔබන්න."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"මුහුණ හඳුනා ගන්නා ලදි. විවෘත කිරීමට ඔබන්න."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"මුහුණ හඳුනා ගන්නා ලදි. විවෘත කිරීමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"වමට ගෙන යන්න"</item>
<item msgid="5558598599408514296">"පහළට ගෙන යන්න"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ඔව්, දිගටම කරගෙන යන්න"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"ආගන්තුක ප්‍රකාරය"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"ඔබ ආගන්තුක ප්‍රකාරයේ සිටී"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"නව පරිශීලකයෙකු එක් කිරීම ආගන්තුක මාදිලියෙන් පිටවී වත්මන් ආගන්තුක සැසියෙන් සියලුම යෙදුම් සහ දත්ත මකනු ඇත."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"පරිශීලක සීමාවට ළඟා විය"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">ඔබට පරිශීලකයින් <xliff:g id="COUNT">%d</xliff:g>ක් දක්වා එක් කළ හැකිය.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"ඇඟවීම්"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"බැටරිය"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"තිර රු"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"පොදු පණිවිඩ"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"ක්ෂණික යෙදුම්"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"පිහිටුවීම"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"ගබඩාව"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"ඉඟි"</string>
<string name="instant_apps" msgid="8337185853050247304">"ක්ෂණික යෙදුම්"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"කැමරාව"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ස්ථානය"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"මයික්‍රෝෆෝනය"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"තිර පටිගත කිරීම"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"මෙම සැසිය විකාශය කිරීමට, කරුණාකර යෙදුම විවෘත කරන්න."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"නොදන්නා යෙදුම"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"විකාශය නවතන්න"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ශ්‍රව්‍ය ප්‍රතිදානය සඳහා තිබෙන උපාංග."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්‍රියා කරන ආකාරය"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"විකාශනය"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ගැළපෙන බ්ලූටූත් උපාංග සහිත ඔබ අවට සිටින පුද්ගලයින්ට ඔබ විකාශනය කරන මාධ්‍යයට සවන් දිය හැකිය"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"නිමයි"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"පිටපත් කරන ලදි"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> සිට"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"පිටපත් කළ පෙළ අස් කරන්න"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"පිටපත් කළ පෙළ සංස්කරණය කරන්න"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"පිටපත් කළ රූපය සංස්කරණය කරන්න"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"අවට උපාංගය වෙත යවන්න"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"කැමරාව සහ මයික් ක්‍රියාවිරහිතයි"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"විකාශනය කරමින්"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්‍රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ප්‍රතිදානය වෙනස් කරන්න"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"නොදනී"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 8a16acbb7c57..327e0b92c967 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ක්‍රියාවිරහිතයි"</item>
<item msgid="460891964396502657">"ක්‍රියාත්මකයි"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"නොමැත"</item>
+ <item msgid="8014986104355098744">"ක්‍රියාවිරහිතයි"</item>
+ <item msgid="5966994759929723339">"ක්‍රියාත්මකයි"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9817ecfa2274..9ef857ea0d4e 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrdené"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Overenie dokončíte klepnutím na Potvrdiť"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Odomknuté tvárou. Pokračujte klepnutím na ikonu odomknutia"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odomknuté tvárou. Pokračujte stlačením."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Tvár bola rozpoznaná. Pokračujte stlačením."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Tvár bola rozpoznaná. Pokračujte stlačením ikony odomknutia"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Overené"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použiť PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použiť vzor"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Šetrič obrazovky"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Prístup ku kamere"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Prístup k mikrofónu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"K dispozícii"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Otvorte potiahnutím prstom nahor"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Otvorte klepnutím na ikonu odomknutia"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Odomknuté tvárou. Otvorte klepnutím na ikonu odomknutia."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odomknuté tvárou. Otvorte stlačením."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Tvár bola rozpoznaná. Otvorte stlačením."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Tvár bola rozpoznaná. Otvorte stlačením ikony odomknutia."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Posunúť doľava"</item>
<item msgid="5558598599408514296">"Posunúť nadol"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Áno, pokračovať"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Režim pre hostí"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Ste v režime pre hostí"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ak pridáte nového používatelia, ukončí sa režim pre hostí a odstránia sa všetky aplikácie a údaje z aktuálnej relácie hosťa."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Dosiahnutý limit počtu používateľov"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="few">Môžete pridať maximálne <xliff:g id="COUNT">%d</xliff:g> používateľov.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Upozornenia"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batéria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Snímky obrazovky"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Všeobecné správy"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Okamžité aplikácie"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavenie"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Úložisko"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string>
<string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikácie"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofón"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"nahrávanie obrazovky"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ak chcete túto reláciu prenášať, otvorte aplikáciu."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznáma aplikácia"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastaviť prenos"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupné zariadenia pre zvukový výstup."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ako vysielanie funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysielanie"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ľudia v okolí s kompatibilnými zariadeniami s rozhraním Bluetooth si môžu vypočuť médiá, ktoré vysielate"</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopírované"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikácie <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Zrušiť skopírovaný text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Používateľské rozhranie zahodenia kópie"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upraviť skopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upraviť skopírovaný obrázok"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odoslať do zariadenia v okolí"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera a mikrofón sú vypnuté"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# upozornenie}few{# upozornenia}many{# notifications}other{# upozornení}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysiela"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Chcete zastaviť vysielanie aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ak vysielate aplikáciu <xliff:g id="SWITCHAPP">%1$s</xliff:g> alebo zmeníte výstup, aktuálne vysielanie bude zastavené"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysielanie aplikácie <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmena výstupu"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznáme"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index dcdfb3a901b5..3cbde1c9574c 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Vypnuté"</item>
<item msgid="460891964396502657">"Zapnuté"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nedostupné"</item>
+ <item msgid="8014986104355098744">"Vypnuté"</item>
+ <item msgid="5966994759929723339">"Zapnuté"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 857e1df94b74..9b6ab870cb68 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potrjeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Za dokončanje se dotaknite »Potrdite«"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Odklenjeno z obrazom. Za nadaljevanje pritisnite ikono za odklepanje."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odklenjeno z obrazom. Pritisnite za nadaljevanje."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obraz je prepoznan. Pritisnite za nadaljevanje."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obraz je prepoznan. Za nadaljevanje pritisnite ikono za odklepanje."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Preverjena pristnost"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Uporabi kodo PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Uporabi vzorec"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ohranjevalnik zaslona"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostop do fotoaparata"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostop do mikrofona"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Na voljo"</string>
@@ -317,6 +321,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Povlecite navzgor, da odprete"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Za odpiranje pritisnite ikono za odklepanje."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Odklenjeno z obrazom. Za odpiranje pritisnite ikono za odklepanje."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odklenjeno z obrazom. Pritisnite za odpiranje."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Obraz je prepoznan. Pritisnite za odpiranje."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Obraz je prepoznan. Za odpiranje pritisnite ikono za odklepanje."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Premik levo"</item>
<item msgid="5558598599408514296">"Premik navzdol"</item>
@@ -349,6 +356,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nadaljuj"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Način za goste"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Ste v načinu za goste"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Če dodate novega uporabnika, se bo način za goste zaprl, aplikacije in podatki v trenutni seji gosta pa bodo izbrisani."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Omejitev uporabnikov je dosežena"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnika.</item>
@@ -701,7 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Opozorila"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Posnetki zaslona"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Splošna sporočila"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Nenamestljive aplikacije"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavitev"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Shramba"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Namigi"</string>
<string name="instant_apps" msgid="8337185853050247304">"Nenamestljive aplikacije"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokacijo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"snemanje zaslona"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Če želite predvajati to sejo, odprite aplikacijo."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznana aplikacija"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ustavi predvajanje"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Razpoložljive naprave za zvočni izhod"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Oddajanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osebe v bližini z združljivo napravo Bluetooth lahko poslušajo predstavnost, ki jo oddajate."</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Končano"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Opusti kopirano besedilo"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Opusti kopiranje uporabniškega vmesnika"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirano besedilo"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopirano sliko"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošlji v napravo v bližini"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat in mikrofon sta izklopljena."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Oddajanje"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Oddajaj aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Sprememba izhoda"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznano"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index f1ebee4f8f92..e720819b4b60 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Izklopljeno"</item>
<item msgid="460891964396502657">"Vklopljeno"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ni na voljo"</item>
+ <item msgid="8014986104355098744">"Izklopljeno"</item>
+ <item msgid="5966994759929723339">"Vklopljeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 44d9a0dc5ad9..750028ea7f56 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Konfirmuar"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trokit \"Konfirmo\" për ta përfunduar"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"U shkyç me fytyrë. Shtyp ikonën e shkyçjes për të vazhduar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"U shkyç me fytyrë. Shtyp për të vazhduar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Fytyra u njoh. Shtyp për të vazhduar."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Fytyra u njoh. Shtyp ikonën e shkyçjes për të vazhduar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"U vërtetua"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Përdor kodin PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Përdor motivin"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Mbrojtësi i ekranit"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Qasja te kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Qasja te mikrofoni"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"E disponueshme"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Shtyp ikonën e shkyçjes për ta hapur"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"U shkyç me fytyrë. Shtyp ikonën e shkyçjes për ta hapur."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"U shkyç me fytyrë. Shtyp për ta hapur."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Fytyra u njoh. Shtyp për ta hapur."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Fytyra u njoh. Shtyp ikonën e shkyçjes për ta hapur."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Lëvize majtas"</item>
<item msgid="5558598599408514296">"Lëvize poshtë"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Po, vazhdo"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Modaliteti \"vizitor\""</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Je në modalitetin \"vizitor\""</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Shtimi i një përdoruesi të ri do të të nxjerrë nga modaliteti \"vizitor\" dhe do të fshijë të gjitha aplikacionet dhe të dhënat nga sesioni aktual për vizitorë."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"U arrit kufiri i përdoruesve"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Mund të shtosh deri në <xliff:g id="COUNT">%d</xliff:g> përdorues.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Sinjalizimet"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Pamje ekrani"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mesazhe të përgjithshme"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplikacionet e çastit"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurimi"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Hapësira ruajtëse"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugjerimet"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacionet e çastit"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamerën"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vendndodhjen"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonin"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"regjistrim i ekranit"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Hap aplikacionin për të transmetuar këtë seancë."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikacion i panjohur"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ndalo transmetimin"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Pajisjet që ofrohen për daljen e audios."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Si funksionon transmetimi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmetimi"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personat në afërsi me ty me pajisje të përputhshme me Bluetooth mund të dëgjojnë median që ti po transmeton"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"U krye"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"U kopjua"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Nga <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hiq tekstin e kopjuar"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hiq kopjen e ndërfaqes së përdoruesit"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifiko tekstin e kopjuar"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifiko imazhin e kopjuar"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Dërgo te pajisja në afërsi"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dhe mikrofoni janë joaktivë"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# njoftim}other{# njoftime}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Po transmeton"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Të ndalohet transmetimi i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nëse transmeton <xliff:g id="SWITCHAPP">%1$s</xliff:g> ose ndryshon daljen, transmetimi yt aktual do të ndalojë"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmeto <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ndrysho daljen"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"I panjohur"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index e24abf64c6f8..7a09f2450354 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Joaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Nuk ofrohet"</item>
+ <item msgid="8014986104355098744">"Joaktiv"</item>
+ <item msgid="5966994759929723339">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ff027afa03fd..915fab7643e6 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврђено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Додирните Потврди да бисте завршили"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Откључано је лицем. Притисните икону откључавања за наставак"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Откључано је лицем. Притисните да бисте наставили."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лице је препознато. Притисните да бисте наставили."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лице препознато. Притисните икону откључавања за наставак."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Идентитет је потврђен"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користите PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користите шаблон"</string>
@@ -224,6 +227,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аутоматска ротација"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аутоматско ротирање екрана"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Чувар екрана"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Приступ камери"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Приступ микрофону"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
@@ -315,6 +319,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Превуците нагоре да бисте отворили"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Притисните икону откључавања за отварање"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Откључано је лицем. Притисните икону откључавања за отварање"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Откључано је лицем. Притисните да бисте отворили."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Лице је препознато. Притисните да бисте отворили."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Лице препознато. Притисните икону откључавања за отварање."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Померите налево"</item>
<item msgid="5558598599408514296">"Померите надоле"</item>
@@ -347,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, настави"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Режим госта"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Користите режим госта"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Додавањем новог корисника изаћи ћете из режима госта и избрисаћете све апликације и податке из актуелне сесије госта."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут максимални број корисника"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item>
@@ -696,7 +706,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Обавештења"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батерија"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Снимци екрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Опште поруке"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Инстант апликације"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Подешавање"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Меморијски простор"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Савети"</string>
<string name="instant_apps" msgid="8337185853050247304">"Инстант апликације"</string>
@@ -744,7 +755,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локацију"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"снимање екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
@@ -849,10 +859,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Да бисте пребацивали ову сесију, отворите апликацију."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Заустави пребацивање"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступни уређаји за аудио излаз."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционише емитовање"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитовање"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Људи у близини са компатибилним Bluetooth уређајима могу да слушају медијски садржај који емитујете"</string>
@@ -945,7 +951,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано је"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Од: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Одбаци копирани текст"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Одбаци копирање корисничког интерфејса"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Измените копирани текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Измените копирану слику"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Пошаљи на уређај у близини"</string>
@@ -961,4 +967,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон су искључени"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# обавештење}one{# обавештење}few{# обавештења}other{# обавештења}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитовање"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Желите да зауставите емитовање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитујете апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените излаз, актуелно емитовање ће се зауставити"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитујте апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промените излаз"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index 0cef5a66c232..dace491993ba 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Искључено"</item>
<item msgid="460891964396502657">"Укључено"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Искључено"</item>
+ <item msgid="5966994759929723339">"Укључено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 198c389595a1..463f84d89860 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekräftat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Upplåst med ansiktslås. Tryck på ikonen lås upp för att fortsätta."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Upplåst med ansiktslås. Tryck för att fortsätta."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet har identifierats. Tryck för att fortsätta."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Använd pinkod"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd mönster"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Skärmsläckare"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraåtkomst"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonåtkomst"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tillgänglig"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Öppna genom att svepa uppåt"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Tryck på ikonen lås upp för att öppna"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Upplåst med ansiktslås. Tryck på ikonen lås upp för att öppna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Upplåst med ansiktslås. Tryck för att öppna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansiktet har identifierats. Tryck för att öppna."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Flytta åt vänster"</item>
<item msgid="5558598599408514296">"Flytta nedåt"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsätt"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Gästläge"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Du är i gästläge"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Om du lägger till en ny användare avslutas gästläget och alla appar och all data från den aktuella gästsessionen raderas."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Användargränsen har nåtts"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Det går att lägga till upp till <xliff:g id="COUNT">%d</xliff:g> användare.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Aviseringar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skärmbilder"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Allmänna meddelanden"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurering"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string>
<string name="instant_apps" msgid="8337185853050247304">"Snabbappar"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"plats"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"skärminspelning"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öppna appen om du vill casta den här sessionen."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Okänd app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sluta casta"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheter som är tillgängliga för ljudutdata."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Utsändning"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i närheten med kompatibla Bluetooth-enheter kan lyssna på medieinnehåll som du sänder ut"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopierades"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Från <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ta bort kopierad text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Stäng användargränssnittet för kopiering"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redigera kopierad text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redigera kopierad bild"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Skicka till enhet i närheten"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kameran och mikrofonen är avstängda"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sänder"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sänd från <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Byt ljudutgång"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Okänt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index 410a6bc4645f..9e69b00adf64 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Inte tillgängligt"</item>
+ <item msgid="8014986104355098744">"Av"</item>
+ <item msgid="5966994759929723339">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2f1be2421310..8d382514704d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Imethibitishwa"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Gusa Thibitisha ili ukamilishe"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Imefunguliwa kwa kutumia uso wako. Bonyeza aikoni ya kufungua ili uendelee."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Uso umetambuliwa. Bonyeza ili uendelee."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili uendelee."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Umethibitishwa"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Tumia PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Tumia mchoro"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Mahali"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Taswira ya skrini"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Ufikiaji wa kamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ufikiaji wa maikrofoni"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Unapatikana"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Telezesha kidole juu ili ufungue"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Bonyeza aikoni ya kufungua ili ufungue"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Imefunguliwa kwa kutumia uso wako. Bonyeza aikoni ya kufungua ili ufungue."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili ufungue."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Uso umetambuliwa. Bonyeza ili ufungue."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili ufungue."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Sogeza kushoto"</item>
<item msgid="5558598599408514296">"Sogeza chini"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza upya"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ndiyo, endelea"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Matumizi ya wageni"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Unatumia hali ya wageni"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Kuongeza mtumiaji mpya kutaondoa matumizi ya wageni yaliyopo na kufuta programu na data kutoka kwenye kipindi cha mgeni cha sasa."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Umefikia kima cha juu cha watumiaji"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Unaruhusiwa kuongeza hadi watumiaji <xliff:g id="COUNT">%d</xliff:g>.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Arifa"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Betri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Picha za skrini"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Ujumbe wa Jumla"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Programu zinazofunguka papo hapo"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Weka mipangilio"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Hifadhi"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Vidokezo"</string>
<string name="instant_apps" msgid="8337185853050247304">"Programu Zinazofunguka Papo Hapo"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"mahali"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"maikrofoni"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"kurekodi skrini"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ili utume kipindi hiki, tafadhali fungua programu."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Programu isiyojulikana"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Acha kutuma"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Vifaa vya kutoa sauti vilivyopo"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jinsi utangazaji unavyofanya kazi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Tangaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Watu walio karibu nawe wenye vifaa oanifu vya Bluetooth wanaweza kusikiliza maudhui unayoyatangaza"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Imemaliza"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Imenakiliwa"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Kutoka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ondoa maandishi yaliyonakiliwa"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ondoa kiolesura cha nakala"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Badilisha maandishi yaliyonakiliwa"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Badilisha picha iliyonakiliwa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Tuma kwenye kifaa kilicho karibu"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera na maikrofoni zimezimwa"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Arifa #}other{Arifa #}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Inaarifu"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ungependa kusimamisha utangazaji kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ikiwa unatangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g> au unabadilisha maudhui, tangazo lako la sasa litasimamishwa"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Tangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Badilisha maudhui"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Haijulikani"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index 79d29ab7b11e..2f765ef5320a 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Imezimwa"</item>
<item msgid="460891964396502657">"Imewashwa"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Haipatikani"</item>
+ <item msgid="8014986104355098744">"Imezimwa"</item>
+ <item msgid="5966994759929723339">"Imewashwa"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 589d12f95f45..347cf2965c77 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -21,5 +21,10 @@
<dimen name="keyguard_status_view_bottom_margin">40dp</dimen>
<dimen name="bouncer_user_switcher_y_trans">20dp</dimen>
+ <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
+ pages is margin * 2, and that makes tiles page not appear immediately after user swipes to
+ the side -->
+ <dimen name="qs_tiles_page_horizontal_margin">32dp</dimen>
+
<dimen name="qqs_layout_padding_bottom">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index 2abc9e3d6119..4de7bb7ef100 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -29,5 +29,11 @@
<dimen name="notification_panel_margin_horizontal">80dp</dimen>
<dimen name="notification_side_paddings">40dp</dimen>
+
+ <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
+ pages is margin * 2, and that makes tiles page not appear immediately after user swipes to the
+ side -->
+ <dimen name="qs_tiles_page_horizontal_margin">60dp</dimen>
+
<dimen name="notification_section_divider_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 1a0faf28f0be..5b0ae788f88e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. தொடர, அன்லாக் ஐகானை அழுத்துக."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. தொடர அழுத்தவும்."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அழுத்தவும்."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அன்லாக் ஐகானை அழுத்தவும்."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"பின்னைப் பயன்படுத்து"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"பேட்டர்னைப் பயன்படுத்து"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"ஸ்கிரீன் சேவர்"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"கேமரா அணுகல்"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"மைக் அணுகல்"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"கிடைக்கிறது"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"திறப்பதற்கு மேல் நோக்கி ஸ்வைப் செய்யவும்"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"திறக்க, அன்லாக் ஐகானை அழுத்தவும்"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. திறக்க, அன்லாக் ஐகானை அழுத்துக."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. திறக்க அழுத்தவும்."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"முகம் அங்கீகரிக்கப்பட்டது. திறக்க அழுத்தவும்."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"முகம் அங்கீகரிக்கப்பட்டது. திறக்க அன்லாக் ஐகானை அழுத்தவும்."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"இடதுபுறம் நகர்த்துங்கள்"</item>
<item msgid="5558598599408514296">"கீழே நகர்த்துங்கள்"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"தொடரவும்"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"கெஸ்ட் பயன்முறை"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"கெஸ்ட் பயன்முறையில் உள்ளீர்கள்"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"புதிய பயனரைச் சேர்த்தால் கெஸ்ட் பயன்முறையில் இருந்து வெளியேற்றப்படுவீர்கள். மேலும் தற்போதைய கெஸ்ட் அமர்வின் ஆப்ஸ் மற்றும் தரவு அனைத்தும் நீக்கப்படும்."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"பயனர் வரம்பை அடைந்துவிட்டீர்கள்"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> பயனர்கள் வரை சேர்க்க முடியும்.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"பேட்டரி"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ஸ்கிரீன் ஷாட்டுகள்"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"பொதுச் செய்திகள்"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"இன்ஸ்டண்ட் ஆப்ஸ்"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"அமைவு"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"சேமிப்பிடம்"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"குறிப்புகள்"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"கேமரா"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"இருப்பிடம்"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"மைக்ரோஃபோன்"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ஸ்கிரீன் ரெக்கார்டிங்"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"இந்த அமர்வை அலைபரப்ப ஆப்ஸைத் திறங்கள்."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"அறியப்படாத ஆப்ஸ்"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"அலைபரப்புவதை நிறுத்து"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ஆடியோ அவுட்புட்டுக்குக் கிடைக்கும் சாதனங்கள்."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"பிராட்காஸ்ட்"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"நீங்கள் பிராட்காஸ்ட் செய்யும் மீடியாவை அருகிலுள்ளவர்கள் இணக்கமான புளூடூத் சாதனங்கள் மூலம் கேட்கலாம்"</string>
@@ -913,7 +919,7 @@
<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="tap_a_network_to_connect" msgid="1565073330852369558">"இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</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>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"முடிந்தது"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"நகலெடுக்கப்பட்டது"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸிலிருந்து"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"நகலெடுக்கப்பட்ட வார்த்தைகளை மூடுக"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"கிளிப்போர்டு மேலடுக்கை மூடுக"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"நகலெடுத்த வார்த்தைகளைத் திருத்து"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"நகலெடுத்த படத்தைத் திருத்து"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"அருகிலுள்ள சாதனத்திற்கு அனுப்பு"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"கேமராவும் மைக்கும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ஒலிபரப்புதல்"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பு"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"அவுட்புட்டை மாற்று"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"தெரியவில்லை"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 52fca126922e..41f64125753c 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"முடக்கப்பட்டுள்ளது"</item>
<item msgid="460891964396502657">"இயக்கப்பட்டுள்ளது"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"கிடைக்கவில்லை"</item>
+ <item msgid="8014986104355098744">"முடக்கப்பட்டுள்ளது"</item>
+ <item msgid="5966994759929723339">"இயக்கப்பட்டுள்ளது"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ff3ff1a8ea9a..d8eeff620441 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"నిర్ధారించబడింది"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"పూర్తి చేయడానికి \"నిర్ధారించు\" నొక్కండి"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ముఖం ద్వారా అన్‌లాక్ చేయబడింది. కొనసాగించడానికి అన్‌లాక్ చిహ్నాన్ని నొక్కండి."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ముఖం ద్వారా అన్‌లాక్ చేయబడింది. కొనసాగించడానికి నొక్కండి."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ముఖం గుర్తించబడింది. కొనసాగించడానికి నొక్కండి."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ముఖం గుర్తించబడింది. కొనసాగడానికి అన్‌లాక్ చిహ్నం నొక్కండి."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ప్రామాణీకరించబడింది"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"పిన్‌ను ఉపయోగించు"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ఆకృతిని ఉపయోగించు"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ఆటో-రొటేట్‌"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"స్క్రీన్ సేవర్"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"కెమెరా యాక్సెస్"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"మైక్ యాక్సెస్"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"అందుబాటులో ఉంది"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"తెరవడానికి, పైకి స్వైప్ చేయండి"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"తెరవడానికి అన్‌లాక్ చిహ్నాన్ని నొక్కండి"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ముఖం ద్వారా అన్‌లాక్ చేయబడింది. తెరవడానికి అన్‌లాక్ చిహ్నాన్ని నొక్కండి."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ముఖం ద్వారా అన్‌లాక్ చేయబడింది. తెరవడానికి నొక్కండి."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"ముఖం గుర్తించబడింది. తెరవడానికి నొక్కండి."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"ముఖం గుర్తించబడింది. తెరవడానికి అన్‌లాక్ చిహ్నం నొక్కండి."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"ఎడమవైపుగా జరపండి"</item>
<item msgid="5558598599408514296">"కిందికి జరపండి"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"గెస్ట్ మోడ్"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"మీరు గెస్ట్ మోడ్‌లో ఉన్నారు"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"కొత్త యూజర్‌ను జోడించడం వలన గెస్ట్ మోడ్ నుండి వైదొలుగుతుంది. అలాగే ప్రస్తుత గెస్ట్ సెషన్ నుండి అన్ని యాప్‌లతో పాటు మొత్తం డేటా తొలగించబడుతుంది."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">మీరు <xliff:g id="COUNT">%d</xliff:g> వినియోగదారుల వరకు జోడించవచ్చు.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్‌లు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్‌షాట్‌లు"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ మెసేజ్‌లు"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"ఇన్‌స్టంట్ యాప్‌లు"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"సెటప్ చేయండి"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"స్టోరేజ్"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"సూచనలు"</string>
<string name="instant_apps" msgid="8337185853050247304">"ఇన్‌స్టంట్ యాప్‌లు"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"కెమెరా"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"లొకేషన్"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"మైక్రోఫోన్"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"స్క్రీన్ రికార్డింగ్"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ఈ సెషన్‌ను ప్రసారం చేయడానికి, దయచేసి యాప్‌ను తెరవండి."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"తెలియని యాప్"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ప్రసారాన్ని ఆపివేయండి"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ఆడియో అవుట్‌పుట్ కోసం అందుబాటులో ఉన్న పరికరాలు."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ప్రసారం"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"మీకు సమీపంలో ఉన్న వ్యక్తులు అనుకూలత ఉన్న బ్లూటూత్ పరికరాలతో మీరు ప్రసారం చేస్తున్న మీడియాను వినగలరు"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"పూర్తయింది"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"కాపీ అయింది"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> నుండి"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"కాపీ చేసిన టెక్స్ట్‌ను విస్మరించండి"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"కాపీ UIని విస్మరించండి"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"కాపీ చేసిన టెక్స్ట్‌ను ఎడిట్ చేయండి"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"కాపీ చేసిన ఇమేజ్‌లను ఎడిట్ చేయండి"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"సమీపంలోని పరికరానికి పంపండి"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"కెమెరా, మైక్ ఆఫ్‌లో ఉన్నాయి"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్‌లు}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ప్రసారం చేస్తోంది"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్‌పుట్‌ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేయండి"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"అవుట్‌పుట్‌ను మార్చండి"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"తెలియదు"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index 60997928082e..44ba47781ae7 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ఆఫ్"</item>
<item msgid="460891964396502657">"ఆన్"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"అందుబాటులో లేరు"</item>
+ <item msgid="8014986104355098744">"ఆఫ్"</item>
+ <item msgid="5966994759929723339">"ఆన్"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 852ab881cfb3..f31c8772cd86 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ยืนยันแล้ว"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"แตะยืนยันเพื่อดำเนินการให้เสร็จสมบูรณ์"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"ปลดล็อกด้วยใบหน้าแล้ว กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"จดจำใบหน้าได้ กดเพื่อดำเนินการต่อ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ใช้ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ใช้รูปแบบ"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"หมุนอัตโนมัติ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"หมุนหน้าจออัตโนมัติ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"โปรแกรมรักษาหน้าจอ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"พร้อมให้ใช้งาน"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"เลื่อนขึ้นเพื่อเปิด"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"กดไอคอนปลดล็อกเพื่อเปิด"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"ปลดล็อกด้วยใบหน้าแล้ว กดไอคอนปลดล็อกเพื่อเปิด"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อเปิด"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"จดจำใบหน้าได้ กดเพื่อเปิด"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อเปิด"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"เลื่อนนิ้วไปทางซ้าย"</item>
<item msgid="5558598599408514296">"เลื่อนนิ้วลง"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ใช่ ดำเนินการต่อ"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"โหมดผู้ใช้ชั่วคราว"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"คุณอยู่ในโหมดผู้ใช้ชั่วคราว"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"การเพิ่มผู้ใช้ใหม่จะเป็นการออกจากโหมดผู้ใช้ชั่วคราว และจะลบแอปและข้อมูลทั้งหมดจากเซสชันผู้ใช้ชั่วคราวในปัจจุบัน"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"ถึงขีดจำกัดผู้ใช้แล้ว"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">คุณเพิ่มผู้ใช้ได้สูงสุด <xliff:g id="COUNT">%d</xliff:g> คน</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"การแจ้งเตือน"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"แบตเตอรี"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ภาพหน้าจอ"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"ข้อความทั่วไป"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"ตั้งค่า"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"พื้นที่เก็บข้อมูล"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"คำแนะนำ"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant App"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"กล้องถ่ายรูป"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ตำแหน่ง"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ไมโครโฟน"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"การบันทึกหน้าจอ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"โปรดเปิดแอปหากต้องการแคสต์เซสชันนี้"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"แอปที่ไม่รู้จัก"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"หยุดแคสต์"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"อุปกรณ์ที่พร้อมใช้งานสำหรับเอาต์พุตเสียง"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ประกาศ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ผู้ที่อยู่ใกล้คุณและมีอุปกรณ์บลูทูธที่รองรับสามารถรับฟังสื่อที่คุณกำลังออกอากาศได้"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"เสร็จ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"คัดลอกแล้ว"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"จาก <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ปิดข้อความที่คัดลอก"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ปิด UI การคัดลอก"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"แก้ไขข้อความที่คัดลอก"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"แก้ไขรูปภาพที่คัดลอก"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ส่งไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ตั้งปลุกแล้ว"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"กล้องและไมค์ปิดอยู่"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"กำลังออกอากาศ"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"เปลี่ยนเอาต์พุต"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ไม่ทราบ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 4565f35fbef2..9cd060f2cabf 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"ปิด"</item>
<item msgid="460891964396502657">"เปิด"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"ไม่พร้อมใช้งาน"</item>
+ <item msgid="8014986104355098744">"ปิด"</item>
+ <item msgid="5966994759929723339">"เปิด"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index ed56ff6d5542..a646f88d3a9c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Nakumpirma"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"I-tap ang Kumpirmahin para kumpletuhin"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Na-unlock gamit ang mukha. Pindutin ang icon ng unlock para magpatuloy."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Na-unlock gamit ang mukha. Pindutin para magpatuloy."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nakilala ang mukha. Pindutin para magpatuloy."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nakilala ang mukha. Pindutin ang unlock para magpatuloy."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Na-authenticate"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gumamit ng PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gumamit ng pattern"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Screen saver"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Access sa camera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Access sa mic"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Mag-swipe pataas para buksan"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Pindutin ang icon ng unlock para buksan"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Na-unlock gamit ang mukha. Pindutin ang icon ng unlock para buksan."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Na-unlock gamit ang mukha. Pindutin para buksan."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Nakilala ang mukha. Pindutin para buksan."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Nakilala ang mukha. Pindutin ang icon ng unlock para buksan."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Ilipat pakaliwa"</item>
<item msgid="5558598599408514296">"Ibaba"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oo, magpatuloy"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Guest mode"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Naka-guest mode ka"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Kapag nagdagdag ka ng bagong user, aalis sa guest mode at made-delete ang lahat ng app at data mula sa kasalukuyang session ng bisita."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Naabot na ang limitasyon sa user"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Maaari kang magdagdag ng hanggang <xliff:g id="COUNT">%d</xliff:g> user.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Mga Alerto"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Baterya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Mga Screenshot"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Mga Pangkalahatang Mensahe"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Mga Hint"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasyon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikropono"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"pag-record ng screen"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para ma-cast ang session na ito, buksan ang app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Hindi kilalang app"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ihinto ang pag-cast"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Mga available na device para sa audio output."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Makakapakinig ang mga taong malapit sa iyo na may mga compatible na Bluetooth device sa media na bino-broadcast mo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Tapos na"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nakopya"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mula sa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"I-dismiss ang nakopyang text"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"I-dismiss ang UI ng pagkopya"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"I-edit ang kinopyang text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"I-edit ang kinopyang larawan"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ipadala sa kalapit na device"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Naka-off ang camera at mikropono"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Nagbo-broadcast"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"I-broadcast ang <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Baguhin ang output"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Hindi alam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index 59fed0f6b247..cd7dcf51b279 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Naka-off"</item>
<item msgid="460891964396502657">"Naka-on"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Hindi available"</item>
+ <item msgid="8014986104355098744">"Naka-off"</item>
+ <item msgid="5966994759929723339">"Naka-on"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 20571866b69f..807dd81418e5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Onaylandı"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamak için Onayla\'ya dokunun"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Kilit, yüzünüzle açıldı. Kilit açma simgesine basın."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Cihazın kilidini yüzünüzle açtınız. Devam etmek için basın."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yüzünüz tanındı. Devam etmek için basın."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kimliği Doğrulandı"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kullan"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Deseni kullan"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran koruyucu"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera erişimi"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofon erişimi"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Kullanılabilir"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmak için yukarı kaydırın"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Açmak için Kilit açma simgesine basın"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Kilit, yüzünüzle açıldı. Kilit açma simgesine basın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Cihazın kilidini yüzünüzle açtınız. Açmak için basın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Yüzünüz tanındı. Açmak için basın."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Sola taşı"</item>
<item msgid="5558598599408514296">"Aşağı taşı"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Evet, devam et"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Misafir modu"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Misafir modundasınız"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Yeni bir kullanıcı eklendiğinde misafir modundan çıkılarak mevcut misafir oturumundaki tüm uygulamalar ve veriler silinir."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Kullanıcı sınırına ulaşıldı"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">En fazla <xliff:g id="COUNT">%d</xliff:g> kullanıcı ekleyebilirsiniz.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Uyarılar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pil"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ekran görüntüleri"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Genel Mesajlar"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Hazır Uygulamalar"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Kurulum"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Depolama alanı"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"İpuçları"</string>
<string name="instant_apps" msgid="8337185853050247304">"Hazır Uygulamalar"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"konum"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekran kaydı"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu oturumu yayınlamak için lütfen uygulamayı açın."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Bilinmeyen uygulama"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayını durdur"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Ses çıkışı için kullanılabilir cihazlar."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Anons"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Yakınınızda ve uyumlu Bluetooth cihazları olan kişiler yayınladığınız medya içeriğini dinleyebilir"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Bitti"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasından"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopyalanan metni kapat"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopyalanan kullanıcı arayüzünü kapat"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanan metni düzenle"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanan resmi düzenle"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yakındaki cihaza gönder"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ve mikrofon kapalı"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayınlama"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapın"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Çıkışı değiştirme"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Bilinmiyor"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index d06d72715d44..28ba7dcb9010 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Kapalı"</item>
<item msgid="460891964396502657">"Açık"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Kullanılamıyor"</item>
+ <item msgid="8014986104355098744">"Kapalı"</item>
+ <item msgid="5966994759929723339">"Açık"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index aa764b36eff8..c5256f4feadd 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Розблоковано (фейсконтроль). Натисніть значок розблокування."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейсконтроль). Натисніть, щоб продовжити."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Обличчя розпізнано. Натисніть, щоб продовжити."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Обличчя розпізнано. Натисніть значок розблокування."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Автентифіковано"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Ввести PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Намалювати ключ"</string>
@@ -225,6 +228,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматичне обертання"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ до камери"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ до мікрофона"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Дозволено"</string>
@@ -317,12 +321,13 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведіть пальцем угору, щоб відкрити"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Щоб відкрити, натисніть значок розблокування."</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Розблоковано (фейсконтроль). Натисніть значок розблокування."</string>
- <string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Перемістіть палець ліворуч"</item>
- <item msgid="5558598599408514296">"Перемістіть палець униз"</item>
- <item msgid="4844142668312841831">"Перемістіть палець праворуч"</item>
- <item msgid="5640521437931460125">"Перемістіть палець угору"</item>
- </string-array>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Розблоковано (фейсконтроль). Натисніть, щоб відкрити."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Обличчя розпізнано. Натисніть, щоб відкрити."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Обличчя розпізнано. Натисніть значок розблокування."</string>
+ <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
+ <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
<string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
@@ -349,6 +354,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, продовжити"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Режим гостя"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Ви ввійшли в режимі гостя"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Якщо додати нового користувача, ви вийдете з режиму гостя, а всі додатки й дані з поточного сеансу цього режиму буде видалено."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Ви досягли ліміту користувачів"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувача.</item>
@@ -701,7 +709,10 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сповіщення"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Акумулятор"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Знімки екрана"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Загальні повідомлення"</string>
+ <!-- no translation found for notification_channel_instant (7556135423486752680) -->
+ <skip />
+ <!-- no translation found for notification_channel_setup (7660580986090760350) -->
+ <skip />
<string name="notification_channel_storage" msgid="2720725707628094977">"Пам’ять"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Поради"</string>
<string name="instant_apps" msgid="8337185853050247304">"Додатки з миттєвим запуском"</string>
@@ -749,7 +760,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"місце"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрофон"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"запис відео з екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string>
@@ -855,10 +865,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Щоб транслювати цей сеанс, відкрийте додаток."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невідомий додаток"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Припинити трансляцію"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступні пристрої для відтворення звуку."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляція"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Люди поблизу, які мають сумісні пристрої з Bluetooth, можуть слухати медіаконтент, який ви транслюєте."</string>
@@ -952,7 +958,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопійовано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З додатка <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Закрити буфер обміну зі скопійованим текстом"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрити вікно копіювання"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редагувати скопійований текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редагувати скопійоване зображення"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Надіслати на пристрій поблизу"</string>
@@ -968,4 +974,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камеру й мікрофон вимкнено"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляція"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Змінити додаток для трансляції на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змінити аудіовихід"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Невідомо"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index 040fb4d3d6e3..3f6ca461ac1d 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Вимкнено"</item>
<item msgid="460891964396502657">"Увімкнено"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Недоступно"</item>
+ <item msgid="8014986104355098744">"Вимкнено"</item>
+ <item msgid="5966994759929723339">"Увімкнено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index e133c1b5a6e1..4efcc65148f5 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تصدیق شدہ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"مکمل کرنے کیلئے \'تصدیق کریں\' تھپتھپائیں"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"چہرے سے انلاک کیا گیا۔ جاری رکھنے کیلئے انلاک آئیکن دبائیں۔"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"چہرے سے انلاک کیا گیا۔ جاری رکھنے کے لیے دبائیں۔"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کے لیے دبائیں۔"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کیلئے انلاک آئیکن دبائیں۔"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"تصدیق کردہ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‏PIN استعمال کریں"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"پیٹرن کا استعمال کریں"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"اسکرین سیور"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"کیمرا تک رسائی"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"مائیکروفون تک رسائی"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"دستیاب ہے"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"کھولنے کے لیے اوپر سوائپ کريں"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"کھولنے کیلئے انلاک آئیکن دبائیں"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"چہرے سے انلاک کیا گیا۔ کھولنے کیلئے انلاک آئیکن دبائیں۔"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"چہرے سے انلاک کیا گیا۔ کھولنے کے لیے دبائیں۔"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"چہرے کی شناخت ہو گئی۔ کھولنے کے لیے دبائیں۔"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"چہرے کی شناخت ہو گئی۔ کھولنے کیلئے انلاک آئیکن دبائیں۔"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"دائیں منتقل کریں"</item>
<item msgid="5558598599408514296">"نیچے منتقل کریں"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ہاں، جاری رکھیں"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"مہمان وضع"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"آپ مہمان وضع میں ہیں"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"نئے صارف کو شامل کرنے سے مہمان وضع سے باہر نکل جائے گا اور موجودہ مہمان سیشن سے تمام ایپس اور ڈیٹا حذف ہو جائیں گے۔"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"صارف کی حد مکمل ہو گئی"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">صرف <xliff:g id="COUNT">%d</xliff:g> صارفین بنائے جا سکتے ہیں۔</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"الرٹس"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"بیٹری"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"اسکرین شاٹس"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"عمومی پیغامات"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"فوری ایپس"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"سیٹ اپ"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"اسٹوریج"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"اشارات"</string>
<string name="instant_apps" msgid="8337185853050247304">"فوری ایپس"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"کیمرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مقام"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"مائیکروفون"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"اسکرین ریکارڈنگ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"اس سیشن کو کاسٹ کرنے کیلئے، براہ کرم ایپ کھولیں۔"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"نامعلوم ایپ"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"کاسٹ کرنا بند کریں"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"آڈیو آؤٹ پٹ کے لیے دستیاب آلات۔"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"براڈکاسٹنگ کیسے کام کرتا ہے"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"براڈکاسٹ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"موافق بلوٹوتھ آلات کے ساتھ آپ کے قریبی لوگ آپ کے نشر کردہ میڈیا کو سن سکتے ہیں"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ہو گیا"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کاپی کر دیا گیا ہے"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"‫<xliff:g id="APPNAME">%1$s</xliff:g> سے"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"کاپی کردہ ٹیکسٹ برخاست کریں"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"‏کاپی شدہ UI کو برخاست کریں"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"کاپی کردہ ٹیکسٹ میں ترمیم کریں"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"کاپی کردہ تصویر میں ترمیم کریں"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"قریبی آلے کو بھیجیں"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"کیمرا اور مائیک آف ہیں"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اطلاع}other{# اطلاعات}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"نشریات"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> براڈکاسٹنگ روکیں؟"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر آپ <xliff:g id="SWITCHAPP">%1$s</xliff:g> براڈکاسٹ کرتے ہیں یا آؤٹ پٹ کو تبدیل کرتے ہیں تو آپ کا موجودہ براڈکاسٹ رک جائے گا"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> پر براڈکاسٹ کریں"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"آؤٹ پٹ تبدیل کریں"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"نامعلوم"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index 79d2cf6d0624..05aa4e91e5cc 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"آف"</item>
<item msgid="460891964396502657">"آن"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"غیر دستیاب"</item>
+ <item msgid="8014986104355098744">"آف"</item>
+ <item msgid="5966994759929723339">"آن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3fff2600f1a3..c6334299c610 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Tasdiqlangan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tasdiqlash uchun tegining"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Yuz orqali ochilgan. Davom etish uchun ochish belgisini bosing."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Yuz orqali ochildi. Davom etish uchun bosing."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yuz aniqlandi. Davom etish uchun bosing."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yuz aniqlandi. Davom etish uchun ochish belgisini bosing."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Tasdiqlandi"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kod kiritish"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Grafik kalitdan foydalanish"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Ekran lavhasi"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraga ruxsat"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonga ruxsat"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Mavjud"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Ochish uchun tepaga suring"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Ochish uchun ochish belgisini bosing"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Yuz orqali ochilgan. Ochish uchun ochish belgisini bosing."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Yuz orqali ochildi. Ochish uchun bosing."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Yuz aniqlandi. Ochish uchun bosing."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Yuz aniqlandi. Ochish uchun ochish belgisini bosing."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Chapga siljitish"</item>
<item msgid="5558598599408514296">"Pastga siljitish"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Seansni davom ettirmoqchimisiz?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Boshidan boshlansin"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ha, davom ettirilsin"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Mehmon rejimi"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Mehmon rejimidasiz"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Yangi foydalanuvchi kiritilsa, mehmon rejimi tark etiladi va joriy mehmon seansidagi barcha ilova va ularning maʼlumotlari tozalanadi."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limitga yetib keldi"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tagacha foydalanuvchi qo‘shish mumkin.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Bildirishnomalar"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batareya"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skrinshotlar"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Umumiy xabarlar"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Darhol ochiladigan ilovalar"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Sozlash"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Xotira"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Maslahatlar"</string>
<string name="instant_apps" msgid="8337185853050247304">"Darhol ochiladigan ilovalar"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"joylashuv"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekranni yozuvi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani juftlash"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu seansni translatsiya qilish uchun ilovani oching."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Notanish ilova"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Toʻxtatish"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio chiqish uchun mavjud qurilmalar."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Translatsiya qanday ishlaydi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Translatsiya"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Atrofingizdagi mos Bluetooth qurilmasiga ega foydalanuvchilar siz translatsiya qilayotgan mediani tinglay olishadi"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Tayyor"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nusxa olindi"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Manba: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Nusxalangan matnni yopish"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI nusxasini bekor qilish"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Nusxa olingan matnni tahrirlash"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Nusxa olingan rasmni tahrirlash"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaqin-atrofdagi qurilmaga yuborish"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera va mikrofon yoqilmagan"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ta bildirishnoma}other{# ta bildirishnoma}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Signal uzatish"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga translatsiya toʻxtatilsinmi?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Agar <xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya qilsangiz yoki ovoz chiqishini oʻzgartirsangiz, joriy translatsiya toʻxtab qoladi"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ovoz chiqishini oʻzgartirish"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Noaniq"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index b6875974d2de..a84f7698d861 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Oʻchiq"</item>
<item msgid="460891964396502657">"Yoniq"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Bandman"</item>
+ <item msgid="8014986104355098744">"Oʻchiq"</item>
+ <item msgid="5966994759929723339">"Yoniq"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 7a0f00eb5157..516930dc4f74 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ðã xác nhận"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Nhấn vào Xác nhận để hoàn tất"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Đã mở khoá bằng khuôn mặt. Nhấn biểu tượng mở khoá để tiếp tục."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Đã mở khoá bằng khuôn mặt. Hãy nhấn để tiếp tục."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Đã nhận diện khuôn mặt. Hãy nhấn để tiếp tục."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để tiếp tục."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Đã xác thực"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Dùng mã PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Dùng hình mở khóa"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Trình bảo vệ màn hình"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Truy cập máy ảnh"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Truy cập micrô"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Được phép"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Vuốt lên để mở"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Nhấn biểu tượng mở khoá để mở"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Đã mở khoá bằng khuôn mặt. Nhấn biểu tượng mở khoá để mở."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Đã mở khoá bằng khuôn mặt. Nhấn để mở."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Đã nhận diện khuôn mặt. Nhấn để mở."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để mở."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Di chuyển sang trái"</item>
<item msgid="5558598599408514296">"Di chuyển xuống"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Có, tiếp tục"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Chế độ khách"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Bạn đang ở chế độ khách"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Khi thêm người dùng mới, chế độ khách sẽ bị thoát và mọi ứng dụng cũng như dữ liệu trong phiên khách hiện tại sẽ bị xoá."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Đã đạt đến giới hạn người dùng"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">Bạn có thể thêm tối đa <xliff:g id="COUNT">%d</xliff:g> người dùng.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Cảnh báo"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pin"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Ảnh chụp màn hình"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Thông báo chung"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Ứng dụng tức thì"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Thiết lập"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Bộ nhớ"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Gợi ý"</string>
<string name="instant_apps" msgid="8337185853050247304">"Ứng dụng tức thì"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"máy ảnh"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vị trí"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrô"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ghi màn hình"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Vui lòng mở ứng dụng để truyền phiên này."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ứng dụng không xác định"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dừng truyền"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Các thiết bị có sẵn để xuất âm thanh."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Truyền"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Những người ở gần có thiết bị Bluetooth tương thích có thể nghe nội dung nghe nhìn bạn đang truyền"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Xong"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Đã sao chép"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Từ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Loại bỏ văn bản đã sao chép"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Đóng giao diện người dùng sao chép"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Chỉnh sửa văn bản đã sao chép"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Chỉnh sửa hình ảnh đã sao chép"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Gửi đến thiết bị ở gần"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Máy ảnh và micrô đang tắt"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Phát sóng"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Phát <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Thay đổi đầu ra"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Không xác định"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 827c72ae2867..482a32f902b4 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Đang tắt"</item>
<item msgid="460891964396502657">"Đang bật"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Không có sẵn"</item>
+ <item msgid="8014986104355098744">"Tắt"</item>
+ <item msgid="5966994759929723339">"Đang bật"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2ce422b7d3e6..b0e587f2593c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已确认"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"点按“确认”即可完成"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"已通过面孔识别解锁。按下解锁图标即可继续。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已通过面孔识别解锁。点按即可继续。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"识别出面孔。点按即可继续。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"识别出面孔。按下解锁图标即可继续。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已经过身份验证"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 码"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用图案"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动旋转屏幕"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"屏保"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"摄像头使用权限"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麦克风使用权限"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"已允许"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑动即可打开"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"按下解锁图标即可打开"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"已通过面孔识别解锁。按下解锁图标即可打开。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"已通过面孔识别解锁。点按即可打开。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"识别出面孔。点按即可打开。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"识别出面孔。按下解锁图标即可打开。"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"左移"</item>
<item msgid="5558598599408514296">"下移"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,继续"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"访客模式"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"您当前处于访客模式"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"如果添加新用户,系统将退出访客模式并删除当前访客会话中的所有应用和数据。"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"已达到用户数上限"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">您最多可以添加 <xliff:g id="COUNT">%d</xliff:g> 位用户。</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"提醒"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"电池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"屏幕截图"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"常规消息"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"免安装应用"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"设置"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"存储空间"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安装应用"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相机"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置信息"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麦克风"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"屏幕录制"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如需投射此会话,请打开相关应用。"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"未知应用"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投射"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"音频输出的可用设备。"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"广播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近使用兼容蓝牙设备的用户可以收听您广播的媒体内容"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已复制"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"来自<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"忽略复制的文字"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"关闭复制界面"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"修改所复制的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"编辑所复制的图片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"发送到附近的设备"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"摄像头和麦克风已关闭"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"正在广播"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"更改输出来源"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"未知"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 3c628721aa5b..b476255bc669 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"已关闭"</item>
<item msgid="460891964396502657">"已开启"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"不可用"</item>
+ <item msgid="8014986104355098744">"关闭"</item>
+ <item msgid="5966994759929723339">"开启"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5ef2f3d0f7d0..30cf7da73079 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"已使用面孔解鎖。按解鎖圖示即可繼續。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已使用面孔解鎖。按下即可繼續操作。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"已識別面孔。按下即可繼續操作。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"已識別面孔。按解鎖圖示即可繼續。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"驗證咗"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用圖案"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"螢幕保護程式"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"允許"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"按解鎖圖示即可開啟"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"已使用面孔解鎖。按解鎖圖示即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"已使用面孔解鎖。按下即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"已識別面孔。按下即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"已識別面孔。按解鎖圖示即可開啟。"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"向左移"</item>
<item msgid="5558598599408514296">"向下移"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是的,請繼續"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"訪客模式"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"您正在使用訪客模式"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"新增使用者後,系統就會結束訪客模式,並刪除目前訪客工作階段中的所有應用程式和資料。"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"已達到使用者上限"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">您可以加入多達 <xliff:g id="COUNT">%d</xliff:g> 個使用者。</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"通知"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"電池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"螢幕擷取畫面"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般訊息"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"免安裝應用程式"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"設定"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"錄製螢幕畫面"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放此工作階段,請開啟應用程式。"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明應用程式"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用作音訊輸出的裝置"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近有兼容藍牙裝置的人可收聽您正在廣播的媒體內容"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"關閉剪貼簿"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿使用者介面"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯已複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯已複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送至附近的裝置"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"已設定鬧鐘"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"相機和麥克風已關閉"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index ee4106639a67..ab8e961a1f47 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"關閉"</item>
<item msgid="460891964396502657">"開啟"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"無法使用"</item>
+ <item msgid="8014986104355098744">"已關閉"</item>
+ <item msgid="5966994759929723339">"已開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index bc3d9c405239..40d58176d02c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認完畢"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕觸 [確認] 完成驗證設定"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"裝置已透過人臉解鎖,按下「解鎖」圖示即可繼續操作。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"裝置已透過你的臉解鎖,按下即可繼續操作。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"臉孔辨識完成,按下即可繼續操作。"</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"臉孔辨識完成,按下「解鎖」圖示即可繼續操作。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已通過驗證"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 碼"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用解鎖圖案"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"螢幕保護程式"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"可以使用"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"按下「解鎖」圖示即可開啟"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"裝置已透過人臉解鎖,按下「解鎖」圖示即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"裝置已透過你的臉解鎖,按下即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"臉孔辨識完成,按下即可開啟。"</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"臉孔辨識完成,按下「解鎖」圖示即可開啟。"</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"向左移"</item>
<item msgid="5558598599408514296">"向下移"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,繼續"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"訪客模式"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"你目前處於訪客模式"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"新增使用者後,系統就會結束訪客模式,並刪除目前訪客工作階段中的所有應用程式和資料。"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"已達使用者數量上限"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="other">最多可新增 <xliff:g id="COUNT">%d</xliff:g> 位使用者。</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"快訊"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"電池"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"螢幕截圖"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"一般訊息"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"免安裝應用程式"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"設定"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string>
<string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"錄製螢幕畫面"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放這個工作階段,請開啟應用程式。"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明的應用程式"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用於輸出音訊的裝置。"</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"如果附近的人有相容的藍牙裝置,就可以聽到你正在廣播的媒體內容"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"關閉剪貼簿"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿 UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送到鄰近裝置"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"鬧鐘設定成功"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"已關閉相機和麥克風"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 1f707408b95b..3d6a546e6103 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"已關閉"</item>
<item msgid="460891964396502657">"已開啟"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"無法使用"</item>
+ <item msgid="8014986104355098744">"已關閉"</item>
+ <item msgid="5966994759929723339">"已開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 398dae5e21e8..68792d1f9dc1 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -137,6 +137,9 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kuqinisekisiwe"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Thepha okuthi Qinisekisa ukuze uqedele"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Ivulwe ngobuso. Cindezela isithonjana sokuvula ukuze uqhubeke."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Vula ngobuso. Cindezela ukuze uqhubeke."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ubuso buyaziwa. Cindezela ukuze uqhubeke."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uqhubeke."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kugunyaziwe"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Sebenzisa iphinikhodi"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Sebenzisa iphethini"</string>
@@ -223,6 +226,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Isilondolozi sesikrini"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Ukufinyelela kwekhamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Ukufinyelela kwe-mic"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Iyatholakala"</string>
@@ -313,6 +317,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Swayiphela phezulu ukuze uvule"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Cindezela isithonjana sokuvula ukuze uvule"</string>
<string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Ivulwe ngobuso. Cindezela isithonjana sokuvula ukuze uvule."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Vula ngobuso. Cindezela ukuze uvule."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ubuso buyaziwa. Cindezela ukuze uvule."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uvule."</string>
<string-array name="udfps_accessibility_touch_hints">
<item msgid="1901953991150295169">"Yisa kwesokunxele"</item>
<item msgid="5558598599408514296">"Yehlisa"</item>
@@ -345,6 +352,9 @@
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yebo, qhubeka"</string>
+ <string name="guest_notification_app_name" msgid="2110425506754205509">"Imodi yesivakashi"</string>
+ <string name="guest_notification_session_active" msgid="5567273684713471450">"Usemodini yesivakashi"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ukwengeza umsebenzisi omusha kuzokhipha imodi yesivakashi futhi kusule wonke ama-app nedatha kusuka esikhathini sesihambeli samanje."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Kufinyelelwe kumkhawulo womsebenzisi"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
<item quantity="one">Ungangeza kufikela kubasebenzisi abangu-<xliff:g id="COUNT">%d</xliff:g>.</item>
@@ -691,7 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Izexwayiso"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Ibhethri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Izithombe-skrini"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Imilayezo ejwayelekile"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Ama-App Asheshayo"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Ukusetha"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Isitoreji"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Ukubonisa"</string>
<string name="instant_apps" msgid="8337185853050247304">"Izinhlelo zokusebenza ezisheshayo"</string>
@@ -739,7 +750,6 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ikhamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"indawo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"imakrofoni"</string>
- <string name="privacy_type_media_projection" msgid="8136723828804251547">"ukurekhoda isikrini"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string>
@@ -843,10 +853,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ukuze usakaze le seshini, sicela uvule i-app."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"I-app engaziwa"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Misa ukusakaza"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Amadivayisi atholakalayo okukhipha umsindo."</string>
- <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
- <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Sakaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Abantu abaseduze nawe abanamadivayisi e-Bluetooth ahambisanayo bangalalela imidiya oyisakazayo"</string>
@@ -938,7 +944,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Kwenziwe"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Ikopishiwe"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Kusukela ku-<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Chitha umbhalo okopishiwe"</string>
+ <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Chitha ukukopisha i-UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Hlela umbhalo okopishiwe"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Hlela umfanekiso okopishiwe"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Thumela kudivayisi eseduze"</string>
@@ -954,4 +960,10 @@
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Ikhamera nemakrofoni kuvaliwe"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string>
+ <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Ukusakaza"</string>
+ <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string>
+ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Shintsha okuphumayo"</string>
+ <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Akwaziwa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index cc8bbb071449..81c46364a9fd 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -171,4 +171,9 @@
<item msgid="146088982397753810">"Valiwe"</item>
<item msgid="460891964396502657">"Vuliwe"</item>
</string-array>
+ <string-array name="tile_states_dream">
+ <item msgid="6184819793571079513">"Ayitholakali"</item>
+ <item msgid="8014986104355098744">"Valiwe"</item>
+ <item msgid="5966994759929723339">"Vuliwe"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 74e46933b784..5cb7d46d20a6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -87,7 +87,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream
</string>
<!-- The tiles to display in QuickSettings -->
@@ -438,6 +438,9 @@
they were added. -->
<integer name="config_smart_replies_in_notifications_onclick_init_delay">200</integer>
+ <!-- Smartspace trampoline activity that is used when the user taps smartspace. -->
+ <string name="config_smartspaceTrampolineActivityComponent" translatable="false">com.google.android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity</string>
+
<!-- Screenshot editing default activity. Must handle ACTION_EDIT image/png intents.
Blank sends the user to the Chooser first.
This name is in the ComponentName flattened format (package/class) -->
@@ -611,6 +614,12 @@
2 - Override the setting to never bypass keyguard -->
<integer name="config_face_unlock_bypass_override">0</integer>
+ <!-- Which face help messages to surface when fingerprint is also enrolled.
+ Message ids correspond with the acquired ids in BiometricFaceConstants -->
+ <integer-array name="config_face_help_msgs_when_fingerprint_enrolled">
+ <!-- for example: <item>26</item> for FACE_ACQUIRED_MOUTH_COVERING_DETECTED -->
+ </integer-array>
+
<!-- Whether the communal service should be enabled -->
<bool name="config_communalServiceEnabled">false</bool>
@@ -619,11 +628,11 @@
<!-- This value is used when calculating whether the device is in ambient light mode. It is
light mode when the light sensor sample value exceeds above this value. -->
- <integer name="config_ambientLightModeThreshold">5</integer>
+ <integer name="config_ambientLightModeThreshold">10</integer>
<!-- This value is used when calculating whether the device is in ambient dark mode. It is
dark mode when the light sensor sample value drops below this value. -->
- <integer name="config_ambientDarkModeThreshold">2</integer>
+ <integer name="config_ambientDarkModeThreshold">5</integer>
<!-- This value is used when calculating whether the device is in ambient light mode. Each
sample contains light sensor events from this span of time duration. -->
@@ -687,7 +696,7 @@
<string name="config_communalSourceConnector" translatable="false"></string>
<!-- How often in milliseconds to jitter the dream overlay in order to avoid burn-in. -->
- <integer name="config_dreamOverlayBurnInProtectionUpdateIntervalMillis">500</integer>
+ <integer name="config_dreamOverlayBurnInProtectionUpdateIntervalMillis">1000</integer>
<!-- How long in milliseconds before full burn-in protection is achieved. -->
<integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 40664992ba59..8b0bd429939d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -48,7 +48,50 @@
<!-- The minimum display position of the arrow on the screen -->
<dimen name="navigation_edge_arrow_min_y">64dp</dimen>
<!-- The amount by which the arrow is shifted to avoid the finger-->
- <dimen name="navigation_edge_finger_offset">48dp</dimen>
+ <dimen name="navigation_edge_finger_offset">64dp</dimen>
+
+ <!-- The thickness of the arrow -->
+ <dimen name="navigation_edge_arrow_thickness">4dp</dimen>
+ <!-- The minimum delta needed to change direction / stop triggering back -->
+ <dimen name="navigation_edge_minimum_x_delta_for_switch">32dp</dimen>
+
+ <!-- entry state -->
+ <dimen name="navigation_edge_entry_margin">4dp</dimen>
+ <dimen name="navigation_edge_entry_background_width">8dp</dimen>
+ <dimen name="navigation_edge_entry_background_height">60dp</dimen>
+ <dimen name="navigation_edge_entry_edge_corners">6dp</dimen>
+ <dimen name="navigation_edge_entry_far_corners">6dp</dimen>
+ <dimen name="navigation_edge_entry_arrow_length">10dp</dimen>
+ <dimen name="navigation_edge_entry_arrow_height">7dp</dimen>
+
+ <!-- pre-threshold -->
+ <dimen name="navigation_edge_pre_threshold_margin">4dp</dimen>
+ <dimen name="navigation_edge_pre_threshold_background_width">64dp</dimen>
+ <dimen name="navigation_edge_pre_threshold_background_height">60dp</dimen>
+ <dimen name="navigation_edge_pre_threshold_edge_corners">22dp</dimen>
+ <dimen name="navigation_edge_pre_threshold_far_corners">26dp</dimen>
+
+ <!-- post-threshold / active -->
+ <dimen name="navigation_edge_active_margin">14dp</dimen>
+ <dimen name="navigation_edge_active_background_width">60dp</dimen>
+ <dimen name="navigation_edge_active_background_height">60dp</dimen>
+ <dimen name="navigation_edge_active_edge_corners">30dp</dimen>
+ <dimen name="navigation_edge_active_far_corners">30dp</dimen>
+ <dimen name="navigation_edge_active_arrow_length">8dp</dimen>
+ <dimen name="navigation_edge_active_arrow_height">9dp</dimen>
+
+ <!-- stretch @412 dp -->
+ <dimen name="navigation_edge_stretch_threshold">412dp</dimen>
+ <dimen name="navigation_edge_stretch_margin">18dp</dimen>
+ <dimen name="navigation_edge_stretch_background_width">74dp</dimen>
+ <dimen name="navigation_edge_stretch_background_height">60dp</dimen>
+ <dimen name="navigation_edge_stretch_left_corners">30dp</dimen>
+ <dimen name="navigation_edge_stretch_right_corners">30dp</dimen>
+ <dimen name="navigation_edge_stretched_arrow_length">7dp</dimen>
+ <dimen name="navigation_edge_stretched_arrow_height">10dp</dimen>
+
+ <dimen name="navigation_edge_cancelled_arrow_length">12dp</dimen>
+ <dimen name="navigation_edge_cancelled_arrow_height">0dp</dimen>
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
@@ -1037,6 +1080,9 @@
<!-- 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>
+ <!-- How far from the right edge of the screen you need to drag the window before the button
+ repositions to the other side. -->
+ <dimen name="magnification_button_reposition_threshold_from_edge">32dp</dimen>
<!-- Home Controls -->
<dimen name="controls_header_menu_size">48dp</dimen>
@@ -1464,4 +1510,18 @@
<dimen name="media_output_broadcast_info_title_height">24dp</dimen>
<dimen name="media_output_broadcast_info_summary_height">20dp</dimen>
<dimen name="media_output_broadcast_info_edit">18dp</dimen>
+
+ <!-- Broadcast dialog -->
+ <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin">16dp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_subtitle_text_size">14sp</dimen>
+ <dimen name="broadcast_dialog_icon_size">24dp</dimen>
+ <dimen name="broadcast_dialog_icon_margin_top">25dp</dimen>
+ <dimen name="broadcast_dialog_btn_radius">100dp</dimen>
+ <dimen name="broadcast_dialog_btn_margin_bottom">4dp</dimen>
+ <dimen name="broadcast_dialog_btn_text_size">16sp</dimen>
+ <dimen name="broadcast_dialog_btn_minHeight">44dp</dimen>
+ <dimen name="broadcast_dialog_margin">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 99f4c767c0de..2b33009498ab 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -341,6 +341,12 @@
<string name="biometric_dialog_tap_confirm">Tap Confirm to complete</string>
<!-- Message shown when a biometric has authenticated with a user's face and is waiting for the user to confirm authentication [CHAR LIMIT=60]-->
<string name="biometric_dialog_tap_confirm_with_face">Unlocked by face. Press the unlock icon to continue.</string>
+ <!-- Message shown when a biometric has authenticated with a user's face and is waiting for the user to confirm authentication [CHAR LIMIT=60]-->
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1">Unlocked by face. Press to continue.</string>
+ <!-- Message shown when a biometric has authenticated with a user's face and is waiting for the user to confirm authentication [CHAR LIMIT=60]-->
+ <string name="biometric_dialog_tap_confirm_with_face_alt_2">Face recognized. Press to continue.</string>
+ <!-- Message shown when a biometric has authenticated with a user's face and is waiting for the user to confirm authentication [CHAR LIMIT=60]-->
+ <string name="biometric_dialog_tap_confirm_with_face_alt_3">Face recognized. Press the unlock icon to continue.</string>
<!-- Talkback string when a biometric is authenticated [CHAR LIMIT=NONE] -->
<string name="biometric_dialog_authenticated">Authenticated</string>
@@ -572,6 +578,8 @@
<!-- QuickSettings: Location [CHAR LIMIT=NONE] -->
<string name="quick_settings_location_label">Location</string>
<!-- QuickSettings: Location (Off) [CHAR LIMIT=NONE] -->
+ <!-- QuickSettings: Screen saver [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_screensaver_label">Screen saver</string>
<!-- QuickSettings: Camera [CHAR LIMIT=NONE] -->
<string name="quick_settings_camera_label">Camera access</string>
<!-- QuickSettings: Microphone [CHAR LIMIT=NONE] -->
@@ -803,6 +811,13 @@
<!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
<string name="keyguard_face_successful_unlock_press">Unlocked by face. Press the unlock icon to open.</string>
+ <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
+ <string name="keyguard_face_successful_unlock_press_alt_1">Unlocked by face. Press to open.</string>
+ <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
+ <string name="keyguard_face_successful_unlock_press_alt_2">Face recognized. Press to open.</string>
+ <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
+ <string name="keyguard_face_successful_unlock_press_alt_3">Face recognized. Press the unlock icon to open.</string>
+
<!-- Messages shown when users press outside of udfps region during -->
<string-array name="udfps_accessibility_touch_hints">
@@ -898,6 +913,17 @@
<!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] -->
<string name="guest_wipe_session_dontwipe">Yes, continue</string>
+ <!-- App name of the notification when guest mode is entered [CHAR LIMIT=35] -->
+ <string name="guest_notification_app_name">Guest mode</string>
+ <!-- Title of the notification when guest mode is entered [CHAR LIMIT=35] -->
+ <string name="guest_notification_session_active">You are in guest mode</string>
+
+ <!-- Additional message for add user confirmation dialog that is appended when current user is
+ guest and guest is ephemeral. This is to warn users that current guest session
+ would get removed after a new user is added and switched to [CHAR LIMIT=none] -->
+ <string name="user_add_user_message_guest_remove">\n\nAdding a new user will exit guest mode
+ and delete all apps and data from the current guest session.</string>
+
<!-- Title for the dialog that lets users know that the maximum allowed number of users on the device has been reached. [CHAR LIMIT=35]-->
<string name="user_limit_reached_title">User limit reached</string>
@@ -1883,8 +1909,10 @@
<string name="notification_channel_battery">Battery</string>
<!-- Title for the notification channel dedicated to screenshot progress. [CHAR LIMIT=NONE] -->
<string name="notification_channel_screenshot">Screenshots</string>
- <!-- Title for the notification channel for miscellaneous notices. [CHAR LIMIT=NONE] -->
- <string name="notification_channel_general">General Messages</string>
+ <!-- Title for the notification channel for instant app notices. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_instant">Instant Apps</string>
+ <!-- Title for the notification channel for setup notices. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_setup">Setup</string>
<!-- Title for the notification channel for problems with storage (i.e. low disk). [CHAR LIMIT=NONE] -->
<string name="notification_channel_storage">Storage</string>
<!-- Title for the notification channel for hints and suggestions. [CHAR LIMIT=NONE] -->
@@ -2531,4 +2559,18 @@
=1 {# notification}
other {# notifications}
}</string>
+
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is broadcasting -->
+ <string name="broadcasting_description_is_broadcasting">Broadcasting</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, title -->
+ <string name="bt_le_audio_broadcast_dialog_title">Stop broadcasting <xliff:g id="app_name" example="App Name 1">%1$s</xliff:g>?</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, sub-title -->
+ <string name="bt_le_audio_broadcast_dialog_sub_title">If you broadcast <xliff:g id="switchApp" example="App Name 2">%1$s</xliff:g> or change the output, your current broadcast will stop</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, switch to others app. -->
+ <string name="bt_le_audio_broadcast_dialog_switch_app">Broadcast <xliff:g id="switchApp" example="App Name 2">%1$s</xliff:g></string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, different output. -->
+ <string name="bt_le_audio_broadcast_dialog_different_output">Change output</string>
+ <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is unknown -->
+ <string name="bt_le_audio_broadcast_dialog_unknown_name">Unknown</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0c25f5473416..4ca6e3ab3dc1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -490,7 +490,7 @@
<style name="MediaOutputItemInactiveTitle">
<item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/media_dialog_item_main_content</item>
+ <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
</style>
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -1196,4 +1196,48 @@
<item name="android:shadowColor">@color/keyguard_shadow_color</item>
<item name="android:shadowRadius">?attr/shadowRadius</item>
</style>
+
+ <style name="BroadcastDialogTitleStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogTitle</item>
+ <item name="android:layout_marginStart">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginEnd">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginTop">@dimen/broadcast_dialog_title_text_margin_top</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogTitle" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_title_text_size</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogBodyStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogSubTitle</item>
+ <item name="android:layout_margin">@dimen/broadcast_dialog_title_text_margin</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogSubTitle" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_subtitle_text_size</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogButtonStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogButton</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:gravity">center</item>
+ <item name="android:stateListAnimator">@null</item>
+ <item name="android:elevation">0dp</item>
+ <item name="android:minHeight">@dimen/broadcast_dialog_btn_minHeight</item>
+ <item name="android:background">@drawable/broadcast_dialog_btn_bg</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogButton" parent="@android:style/TextAppearance.DeviceDefault.Headline">
+ <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
+ <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index e2734164161f..c8095510e2c2 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -308,4 +308,14 @@
<item>Off</item>
<item>On</item>
</string-array>
+
+ <!-- State names for dream (screensaver) tile: unavailable, off, on.
+ This subtitle is shown when the tile is in that particular state but does not set its own
+ subtitle, so some of these may never appear on screen. They should still be translated as
+ if they could appear. [CHAR LIMIT=32] -->
+ <string-array name="tile_states_dream">
+ <item>Unavailable</item>
+ <item>Off</item>
+ <item>On</item>
+ </string-array>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 3cf5bc1bf13a..114ea657a758 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -47,8 +47,10 @@ android_library {
],
static_libs: [
"PluginCoreLib",
+ "SystemUIUnfoldLib",
"androidx.dynamicanimation_dynamicanimation",
"androidx.concurrent_concurrent-futures",
+ "gson-prebuilt-jar",
"dagger2",
"jsr330",
],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt
new file mode 100644
index 000000000000..916a557d7af8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 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.shared.clocks
+
+import com.android.systemui.plugins.Plugin
+import com.android.systemui.plugins.annotations.ProvidesInterface
+import android.annotation.FloatRange
+import android.graphics.drawable.Drawable
+import android.view.View
+
+/** Identifies a clock design */
+typealias ClockId = String
+
+/** A Plugin which exposes the ClockProvider interface */
+@ProvidesInterface(action = ClockProviderPlugin.ACTION, version = ClockProviderPlugin.VERSION)
+interface ClockProviderPlugin : Plugin, ClockProvider {
+ companion object {
+ const val ACTION = "com.android.systemui.action.PLUGIN_CLOCK_PROVIDER"
+ const val VERSION = 1
+ }
+}
+
+/** Interface for building clocks and providing information about those clocks */
+interface ClockProvider {
+ /** Returns metadata for all clocks this provider knows about */
+ fun getClocks(): List<ClockMetadata>
+
+ /** Initializes and returns the target clock design */
+ fun createClock(id: ClockId): Clock
+
+ /** A static thumbnail for rendering in some examples */
+ fun getClockThumbnail(id: ClockId): Drawable?
+}
+
+/** Interface for controlling an active clock */
+interface Clock {
+ /** A small version of the clock, appropriate for smaller viewports */
+ val smallClock: View
+
+ /** A large version of the clock, appropriate when a bigger viewport is available */
+ val largeClock: View
+
+ /** Callback to update the clock view to the current time */
+ fun onTimeTick()
+
+ /** Sets the level of the AOD transition */
+ fun setAodFraction(@FloatRange(from = 0.0, to = 1.0) fraction: Float)
+}
+
+/** Some data about a clock design */
+data class ClockMetadata(
+ val clockId: ClockId,
+ val name: String
+) \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
new file mode 100644
index 000000000000..32459665e6cf
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 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.shared.clocks
+
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.Log
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.shared.plugins.PluginManager
+import com.google.gson.Gson
+import javax.inject.Inject
+
+private val TAG = ClockRegistry::class.simpleName
+private val DEBUG = true
+const val DEFAULT_CLOCK_ID = "DEFAULT"
+
+typealias ClockChangeListener = () -> Unit
+
+/** ClockRegistry aggregates providers and plugins */
+open class ClockRegistry @Inject constructor(
+ val context: Context,
+ val pluginManager: PluginManager,
+ @Main val handler: Handler
+) {
+ private val gson = Gson()
+ private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
+ private val clockChangeListeners = mutableListOf<ClockChangeListener>()
+ private val settingObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) =
+ clockChangeListeners.forEach { it() }
+ }
+
+ private val pluginListener = object : PluginListener<ClockProviderPlugin> {
+ override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) {
+ val currentId = currentClockId
+ for (clock in plugin.getClocks()) {
+ val id = clock.clockId
+ val current = availableClocks[id]
+ if (current != null) {
+ Log.e(TAG, "Clock Id conflict: $id is registered by both " +
+ "${plugin::class.simpleName} and ${current.provider::class.simpleName}")
+ return
+ }
+
+ availableClocks[id] = ClockInfo(clock, plugin)
+
+ if (currentId == id) {
+ if (DEBUG) {
+ Log.i(TAG, "Current clock ($currentId) was connected")
+ }
+ clockChangeListeners.forEach { it() }
+ }
+ }
+ }
+
+ override fun onPluginDisconnected(plugin: ClockProviderPlugin) {
+ val currentId = currentClockId
+ for (clock in plugin.getClocks()) {
+ availableClocks.remove(clock.clockId)
+
+ if (currentId == clock.clockId) {
+ Log.w(TAG, "Current clock ($currentId) was disconnected")
+ clockChangeListeners.forEach { it() }
+ }
+ }
+ }
+ }
+
+ open var currentClockId: ClockId
+ get() {
+ val json = Settings.Secure.getString(context.contentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE)
+ return gson.fromJson(json, ClockSetting::class.java).clockId
+ }
+ set(value) {
+ val json = gson.toJson(ClockSetting(value, System.currentTimeMillis()))
+ Settings.Secure.putString(context.contentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json)
+ }
+
+ init {
+ pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java)
+ context.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+ false,
+ settingObserver,
+ UserHandle.USER_ALL)
+ }
+
+ fun getClocks(): List<ClockMetadata> = availableClocks.map { (_, clock) -> clock.metadata }
+
+ fun getClockThumbnail(clockId: ClockId): Drawable? =
+ availableClocks[clockId]?.provider?.getClockThumbnail(clockId)
+
+ fun createExampleClock(clockId: ClockId): Clock? = createClock(clockId)
+
+ fun registerClockChangeListener(listener: ClockChangeListener) =
+ clockChangeListeners.add(listener)
+
+ fun unregisterClockChangeListener(listener: ClockChangeListener) =
+ clockChangeListeners.remove(listener)
+
+ fun createCurrentClock(): Clock {
+ val clockId = currentClockId
+ if (!clockId.isNullOrEmpty()) {
+ val clock = createClock(clockId)
+ if (clock != null) {
+ return clock
+ } else {
+ Log.e(TAG, "Clock $clockId not found; using default")
+ }
+ }
+
+ return createClock(DEFAULT_CLOCK_ID)!!
+ }
+
+ private fun createClock(clockId: ClockId): Clock? =
+ availableClocks[clockId]?.provider?.createClock(clockId)
+
+ private data class ClockInfo(
+ val metadata: ClockMetadata,
+ val provider: ClockProvider
+ )
+
+ private data class ClockSetting(
+ val clockId: ClockId,
+ val _applied_timestamp: Long
+ )
+} \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 675dc9b533fb..e9c1acbf7ca0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -243,7 +243,7 @@ public class Task {
return new Task(taskKey,
td != null ? td.getPrimaryColor() : 0,
td != null ? td.getBackgroundColor() : 0,
- taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);
+ taskInfo.supportsMultiWindow, isLocked, td, taskInfo.topActivity);
}
public Task(TaskKey key) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 01f417f147d7..b29dc835a6f4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
+import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -97,6 +98,7 @@ public class RotationButtonController {
@SuppressLint("InlinedApi")
private @WindowInsetsController.Behavior
int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
+ private int mNavBarMode;
private boolean mSkipOverrideUserLockPrefsOnce;
private final int mLightIconColor;
private final int mDarkIconColor;
@@ -397,6 +399,10 @@ public class RotationButtonController {
if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
}
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) {
if (DEFAULT_DISPLAY != displayId) {
return;
@@ -433,7 +439,8 @@ public class RotationButtonController {
*/
@SuppressLint("InlinedApi")
private boolean canShowRotationButton() {
- return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT;
+ return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT
+ || isGesturalMode(mNavBarMode);
}
@DrawableRes
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 618d2d2f213a..76a09b38036c 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
@@ -137,6 +137,8 @@ public class RemoteAnimationAdapterCompat {
float displayH = 0;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
+ // skip changes that we didn't wrap
+ if (!leashMap.containsKey(change.getLeash())) continue;
if (change.getTaskInfo() != null
&& change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
isReturnToHome = change.getMode() == TRANSIT_OPEN
@@ -173,6 +175,8 @@ public class RemoteAnimationAdapterCompat {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = leashMap.get(change.getLeash());
+ // skip changes that we didn't wrap
+ if (leash == null) continue;
final int mode = info.getChanges().get(i).getMode();
// Only deal with independent layers
if (!TransitionInfo.isIndependent(change, info)) continue;
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 9cf482fdf790..4ce110bf7c47 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
@@ -17,7 +17,6 @@
package com.android.systemui.shared.system;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
-import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -32,7 +31,6 @@ import android.app.WindowConfiguration;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.ArrayMap;
-import android.util.IntArray;
import android.util.SparseArray;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -142,21 +140,10 @@ public class RemoteAnimationTargetCompat {
// changes should be ordered top-to-bottom in z
final int mode = change.getMode();
- // Don't move anything that isn't independent within its parents
- if (!TransitionInfo.isIndependent(change, info)) {
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
- t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- return;
- }
-
- final boolean hasParent = change.getParent() != null;
+ t.reparent(leash, info.getRootLeash());
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
- if (!hasParent) {
- t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
- change.getStartAbsBounds().top - info.getRootOffset().y);
- }
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
@@ -196,8 +183,7 @@ public class RemoteAnimationTargetCompat {
.setContainerLayer()
// Initial the surface visible to respect the visibility of the original surface.
.setHidden(false)
- .setParent(change.getParent() == null ? info.getRootLeash()
- : info.getChange(change.getParent()).getLeash())
+ .setParent(info.getRootLeash())
.build();
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
@@ -269,58 +255,32 @@ public class RemoteAnimationTargetCompat {
public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
- final SparseArray<RemoteAnimationTargetCompat> childTaskTargets = new SparseArray<>();
- final IntArray excludedParentTaskIds = new IntArray();
+ final SparseArray<TransitionInfo.Change> childTaskTargets = new SparseArray<>();
for (int i = 0; i < info.getChanges().size(); i++) {
final TransitionInfo.Change change = info.getChanges().get(i);
final boolean changeIsWallpaper =
(change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
if (wallpapers != changeIsWallpaper) continue;
- final RemoteAnimationTargetCompat targetCompat =
- new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
- if (leashMap != null) {
- leashMap.put(change.getLeash(), targetCompat.leash);
- }
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null) {
- // Skip wrapping excluded parent task animate target since it will animate its child
- // tasks instead.
- if (excludedParentTaskIds.binarySearch(taskInfo.taskId) != -1) {
- continue;
- }
-
- // Check if there's a matching child task target in cache.
- RemoteAnimationTargetCompat childTaskTarget = childTaskTargets.get(taskInfo.taskId);
- if (childTaskTarget != null) {
- // Launcher monitors leaf task ids to perform animation, override the target
- // with its child task information so Launcher can animate this parent surface
- // directly with leaf task information.
- targetCompat.taskInfo = childTaskTarget.taskInfo;
- targetCompat.taskId = childTaskTarget.taskId;
- childTaskTargets.remove(taskInfo.taskId);
- }
-
- // Check if it has a parent task, cache its information for later use.
- if (taskInfo.parentTaskId != -1
- && excludedParentTaskIds.binarySearch(taskInfo.parentTaskId) == -1) {
- if (!childTaskTargets.contains(taskInfo.parentTaskId)) {
- // Cache the target amd skip wrapping it info the final animation targets.
- // Otherwise, the child task might get transformed multiple-times with the
- // flow like RecentsView#redrawLiveTile.
- childTaskTargets.put(taskInfo.parentTaskId, targetCompat);
+ if (!wallpapers) {
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ // Children always come before parent since changes are in top-to-bottom z-order.
+ if (taskInfo != null) {
+ if (childTaskTargets.contains(taskInfo.taskId)) {
+ // has children, so not a leaf. Skip.
continue;
}
-
- // There is another child task target cached with the same parent task id.
- // Which means the parent having multiple child tasks in transition. Stop
- // propagate child task info.
- childTaskTarget = childTaskTargets.removeReturnOld(taskInfo.parentTaskId);
- out.add(childTaskTarget);
- excludedParentTaskIds.add(taskInfo.parentTaskId);
+ if (taskInfo.hasParentTask()) {
+ childTaskTargets.put(taskInfo.parentTaskId, change);
+ }
}
}
+ final RemoteAnimationTargetCompat targetCompat =
+ new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
+ if (leashMap != null) {
+ leashMap.put(change.getLeash(), targetCompat.leash);
+ }
out.add(targetCompat);
}
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 de35514be2cb..e9ac26182c7e 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
@@ -21,12 +21,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionFilter.CONTAINER_ORDER_TOP;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -132,16 +134,17 @@ public class RemoteTransitionCompat implements Parcelable {
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw
- // the current going-away task on top of recents, though, so move it to front
+ // the current going-away tasks on top of recents, though, so move them to front.
+ // Note that we divide up the "layer space" into 3 regions each the size of
+ // the change count. This way we can easily move changes into above/below/between
+ // while maintaining their relative ordering.
final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
WindowContainerToken pipTask = null;
WindowContainerToken recentsTask = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
- t.setLayer(leashMap.get(change.getLeash()),
- info.getChanges().size() * 3 - i);
+ for (int i = apps.length - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo taskInfo = apps[i].taskInfo;
+ if (apps[i].mode == MODE_CLOSING) {
+ t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
if (taskInfo == null) {
continue;
}
@@ -154,8 +157,7 @@ public class RemoteTransitionCompat implements Parcelable {
} else if (taskInfo != null
&& taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
// This task is for recents, keep it on top.
- t.setLayer(leashMap.get(change.getLeash()),
- info.getChanges().size() * 3 - i);
+ t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
recentsTask = taskInfo.token;
} else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
recentsTask = taskInfo.token;
@@ -167,7 +169,8 @@ public class RemoteTransitionCompat implements Parcelable {
}
t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
- recentsTask, leashMap, mToken);
+ recentsTask, leashMap, mToken,
+ (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@@ -222,12 +225,13 @@ public class RemoteTransitionCompat implements Parcelable {
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
+ private boolean mKeyguardLocked = false;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB,
ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
WindowContainerToken recentsTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
- IBinder transition) {
+ IBinder transition, boolean keyguardLocked) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -240,6 +244,7 @@ public class RemoteTransitionCompat implements Parcelable {
mRecentsTask = recentsTask;
mLeashMap = leashMap;
mTransition = transition;
+ mKeyguardLocked = keyguardLocked;
}
@SuppressLint("NewApi")
@@ -374,6 +379,10 @@ public class RemoteTransitionCompat implements Parcelable {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mKeyguardLocked && mRecentsTask != null) {
+ if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
+ else wct.restoreTransientOrder(mRecentsTask);
+ }
if (!toHome && mPausingTasks != null && mOpeningLeashes == null) {
// The gesture went back to opening the app rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
@@ -383,16 +392,21 @@ public class RemoteTransitionCompat implements Parcelable {
wct.reorder(mPausingTasks.get(i), true /* onTop */);
t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
}
- if (mRecentsTask != null) {
+ if (!mKeyguardLocked && mRecentsTask != null) {
wct.restoreTransientOrder(mRecentsTask);
}
} else {
- if (!sendUserLeaveHint) {
- for (int i = 0; i < mPausingTasks.size(); ++i) {
+ for (int i = 0; i < mPausingTasks.size(); ++i) {
+ if (!sendUserLeaveHint) {
// This means recents is not *actually* finishing, so of course we gotta
// do special stuff in WMCore to accommodate.
wct.setDoNotPip(mPausingTasks.get(i));
}
+ // Since we will reparent out of the leashes, pre-emptively hide the child
+ // surface to match the leash. Otherwise, there will be a flicker before the
+ // visibility gets committed in Core when using split-screen (in splitscreen,
+ // the leaf-tasks are not "independent" so aren't hidden by normal setup).
+ t.hide(mInfo.getChange(mPausingTasks.get(i)).getLeash());
}
if (mPipTask != null && mPipTransaction != null && sendUserLeaveHint) {
t.show(mInfo.getChange(mPipTask).getLeash());
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
index 4394ecbf79eb..98212e1d91b6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
@@ -25,8 +25,8 @@ import com.android.internal.util.TraceBuffer;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.Queue;
import java.util.function.Consumer;
@@ -50,7 +50,7 @@ public class FrameProtoTracer<P, S extends P, T extends P, R>
private final File mTraceFile;
private final ProtoTraceParams<P, S, T, R> mParams;
private Choreographer mChoreographer;
- private final Queue<T> mPool = new LinkedList<>();
+ private final Queue<T> mPool = new ArrayDeque<>();
private final ArrayList<ProtoTraceable<R>> mTraceables = new ArrayList<>();
private final ArrayList<ProtoTraceable<R>> mTmpTraceables = new ArrayList<>();
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
deleted file mode 100644
index d1b06394b818..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
+++ /dev/null
@@ -1,49 +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.systemui.unfold.config
-
-import android.content.Context
-import android.os.SystemProperties
-
-internal class ResourceUnfoldTransitionConfig(private val context: Context) :
- UnfoldTransitionConfig {
-
- override val isEnabled: Boolean
- get() = readIsEnabledResource() && isPropertyEnabled
-
- override val isHingeAngleEnabled: Boolean
- get() = readIsHingeAngleEnabled()
-
- private val isPropertyEnabled: Boolean
- get() =
- SystemProperties.getInt(
- UNFOLD_TRANSITION_MODE_PROPERTY_NAME, UNFOLD_TRANSITION_PROPERTY_ENABLED) ==
- UNFOLD_TRANSITION_PROPERTY_ENABLED
-
- private fun readIsEnabledResource(): 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)
-}
-
-/**
- * Temporary persistent property to control unfold transition mode.
- *
- * See [com.android.unfold.config.AnimationMode].
- */
-private const val UNFOLD_TRANSITION_MODE_PROPERTY_NAME = "persist.unfold.transition_enabled"
-private const val UNFOLD_TRANSITION_PROPERTY_ENABLED = 1
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
new file mode 100644
index 000000000000..7f2933e44b32
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.unfold.system
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ActivityManagerActivityTypeProvider @Inject constructor(
+ private val activityManager: ActivityManager
+) : CurrentActivityTypeProvider {
+
+ override val isHomeActivity: Boolean?
+ get() {
+ val activityType = activityManager.getRunningTasks(/* maxNum= */ 1)
+ ?.getOrNull(0)?.topActivityType ?: return null
+
+ return activityType == WindowConfiguration.ACTIVITY_TYPE_HOME
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
new file mode 100644
index 000000000000..3b8d318a3a79
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.unfold.system
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DeviceStateManagerFoldProvider @Inject constructor(
+ private val deviceStateManager: DeviceStateManager,
+ private val context: Context
+) : FoldProvider {
+
+ private val callbacks: MutableMap<FoldCallback,
+ DeviceStateManager.DeviceStateCallback> = hashMapOf()
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ val listener = FoldStateListener(context, callback)
+ deviceStateManager.registerCallback(executor, listener)
+ callbacks[callback] = listener
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ val listener = callbacks.remove(callback)
+ listener?.let {
+ deviceStateManager.unregisterCallback(it)
+ }
+ }
+
+ private inner class FoldStateListener(
+ context: Context,
+ listener: FoldCallback
+ ) : DeviceStateManager.FoldStateListener(context, { listener.onFoldUpdated(it) })
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
new file mode 100644
index 000000000000..24ae42ae4db2
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.unfold.system
+
+import android.os.Handler
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
+import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
+import dagger.Binds
+import dagger.Module
+import java.util.concurrent.Executor
+
+/**
+ * Dagger module with system-only dependencies for the unfold animation.
+ * The code that is used to calculate unfold transition progress
+ * depends on some hidden APIs that are not available in normal
+ * apps. In order to re-use this code and use alternative implementations
+ * of these classes in other apps and hidden APIs here.
+ */
+@Module
+abstract class SystemUnfoldSharedModule {
+
+ @Binds
+ abstract fun activityTypeProvider(executor: ActivityManagerActivityTypeProvider):
+ CurrentActivityTypeProvider
+
+ @Binds
+ abstract fun config(config: ResourceUnfoldTransitionConfig): UnfoldTransitionConfig
+
+ @Binds
+ abstract fun foldState(provider: DeviceStateManagerFoldProvider): FoldProvider
+
+ @Binds
+ @UnfoldMain
+ abstract fun mainExecutor(@Main executor: Executor): Executor
+
+ @Binds
+ @UnfoldMain
+ abstract fun mainHandler(@Main handler: Handler): Handler
+
+ @Binds
+ @UnfoldBackground
+ abstract fun backgroundExecutor(@UiBackground executor: Executor): Executor
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
deleted file mode 100644
index b351585de364..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.android.systemui.unfold.updates.hinge
-
-import androidx.core.util.Consumer
-
-internal object EmptyHingeAngleProvider : HingeAngleProvider {
- override fun start() {}
-
- override fun stop() {}
-
- override fun removeCallback(listener: Consumer<Float>) {}
-
- override fun addCallback(listener: Consumer<Float>) {}
-}
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
deleted file mode 100644
index 48a5b12c759a..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.android.systemui.unfold.updates.hinge
-
-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.
- */
-interface HingeAngleProvider : CallbackController<Consumer<Float>> {
- fun start()
- fun stop()
-}
-
-const val FULLY_OPEN_DEGREES = 180f
-const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
index 53c528ff24a8..ec938b219933 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2022 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.unfold.util
import android.content.Context
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
index 19d39d515325..d44598049806 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
@@ -284,6 +284,8 @@ class AnimatableClockView @JvmOverloads constructor(
)
}
+ private val glyphFilter: GlyphCallback? = null // Add text animation tweak here.
+
/**
* Set text style with an optional animation.
*
@@ -315,6 +317,7 @@ class AnimatableClockView @JvmOverloads constructor(
delay = delay,
onAnimationEnd = onAnimationEnd
)
+ textAnimator?.glyphFilter = glyphFilter
} else {
// when the text animator is set, update its start values
onTextAnimatorInitialized = Runnable {
@@ -328,6 +331,7 @@ class AnimatableClockView @JvmOverloads constructor(
delay = delay,
onAnimationEnd = onAnimationEnd
)
+ textAnimator?.glyphFilter = glyphFilter
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 13690f30ab3b..3a6ceb1d5f33 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -50,7 +50,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
@@ -233,21 +232,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
"com.android.settings", "com.android.settings.FallbackHome");
- /**
- * If true, the system is in the half-boot-to-decryption-screen state.
- * Prudently disable lockscreen.
- */
- public static final boolean CORE_APPS_ONLY;
-
- static {
- try {
- CORE_APPS_ONLY = IPackageManager.Stub.asInterface(
- ServiceManager.getService("package")).isOnlyCoreApps();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
private final Context mContext;
private final boolean mIsPrimaryUser;
private final boolean mIsAutomotive;
@@ -275,7 +259,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
- private int mRingMode;
private int mPhoneState;
private boolean mKeyguardIsVisible;
private boolean mCredentialAttempted;
@@ -1511,6 +1494,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
handleFingerprintAuthenticated(userId, isStrongBiometric);
};
+ /**
+ * Propagates a pointer down event to keyguard.
+ */
+ public void onUdfpsPointerDown(int sensorId) {
+ mFingerprintAuthenticationCallback.onUdfpsPointerDown(sensorId);
+ }
+
+ /**
+ * Propagates a pointer up event to keyguard.
+ */
+ public void onUdfpsPointerUp(int sensorId) {
+ mFingerprintAuthenticationCallback.onUdfpsPointerUp(sensorId);
+ }
+
@VisibleForTesting
final FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
= new AuthenticationCallback() {
@@ -1551,15 +1548,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Trace.endSection();
}
+ /**
+ * Note, this is currently called from UdfpsController.
+ */
@Override
public void onUdfpsPointerDown(int sensorId) {
Log.d(TAG, "onUdfpsPointerDown, sensorId: " + sensorId);
requestFaceAuth(true);
- if (isFaceDetectionRunning()) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
- }
}
+ /**
+ * Note, this is currently called from UdfpsController.
+ */
@Override
public void onUdfpsPointerUp(int sensorId) {
Log.d(TAG, "onUdfpsPointerUp, sensorId: " + sensorId);
@@ -1587,9 +1587,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
"faceFailure-" + reason);
handleFaceAuthFailed();
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
}
@Override
@@ -1597,10 +1594,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
Trace.endSection();
-
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
}
@Override
@@ -1611,9 +1604,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
handleFaceError(errMsgId, errString.toString());
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) {
requestActiveUnlock(
@@ -2296,10 +2286,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
updateFaceListeningState(BIOMETRIC_ACTION_START);
}
- public boolean isFaceAuthUserRequested() {
- return mIsFaceAuthUserRequested;
- }
-
/**
* In case face auth is running, cancel it.
*/
@@ -3160,11 +3146,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mSecureCameraLaunched = false;
}
- if (mKeyguardBypassController != null) {
- // LS visibility has changed, so reset deviceEntryIntent
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
-
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
index 336101528450..ade89af81bd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
+++ b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
@@ -22,12 +22,14 @@ import android.animation.TimeInterpolator
import android.animation.ValueAnimator
import android.graphics.Canvas
import android.graphics.Typeface
+import android.graphics.fonts.Font
import android.text.Layout
import android.util.SparseArray
private const val TAG_WGHT = "wght"
private const val DEFAULT_ANIMATION_DURATION: Long = 300
+typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
/**
* This class provides text animation between two styles.
*
@@ -74,6 +76,59 @@ class TextAnimator(
})
}
+ sealed class PositionedGlyph {
+
+ /**
+ * Mutable X coordinate of the glyph position relative from drawing offset.
+ */
+ var x: Float = 0f
+
+ /**
+ * Mutable Y coordinate of the glyph position relative from the baseline.
+ */
+ var y: Float = 0f
+
+ /**
+ * Mutable text size of the glyph in pixels.
+ */
+ var textSize: Float = 0f
+
+ /**
+ * Mutable color of the glyph.
+ */
+ var color: Int = 0
+
+ /**
+ * Immutable character offset in the text that the current font run start.
+ */
+ abstract var runStart: Int
+ protected set
+
+ /**
+ * Immutable run length of the font run.
+ */
+ abstract var runLength: Int
+ protected set
+
+ /**
+ * Immutable glyph index of the font run.
+ */
+ abstract var glyphIndex: Int
+ protected set
+
+ /**
+ * Immutable font instance for this font run.
+ */
+ abstract var font: Font
+ protected set
+
+ /**
+ * Immutable glyph ID for this glyph.
+ */
+ abstract var glyphId: Int
+ protected set
+ }
+
private val typefaceCache = SparseArray<Typeface?>()
fun updateLayout(layout: Layout) {
@@ -84,6 +139,57 @@ class TextAnimator(
return animator.isRunning
}
+ /**
+ * GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
+ *
+ * This callback is called for each glyphs just before drawing the glyphs. This function will
+ * be called with the intrinsic position, size, color, glyph ID and font instance. You can
+ * mutate the position, size and color for tweaking animations.
+ * Do not keep the reference of passed glyph object. The interpolator reuses that object for
+ * avoiding object allocations.
+ *
+ * Details:
+ * The text is drawn with font run units. The font run is a text segment that draws with the
+ * same font. The {@code runStart} and {@code runLimit} is a range of the font run in the text
+ * that current glyph is in. Once the font run is determined, the system will convert characters
+ * into glyph IDs. The {@code glyphId} is the glyph identifier in the font and
+ * {@code glyphIndex} is the offset of the converted glyph array. Please note that the
+ * {@code glyphIndex} is not a character index, because the character will not be converted to
+ * glyph one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
+ * composed from multiple characters.
+ *
+ * Here is an example of font runs: "fin. 終わり"
+ *
+ * Characters : f i n . _ 終 わ り
+ * Code Points: \u0066 \u0069 \u006E \u002E \u0020 \u7D42 \u308F \u308A
+ * Font Runs : <-- Roboto-Regular.ttf --><-- NotoSans-CJK.otf -->
+ * runStart = 0, runLength = 5 runStart = 5, runLength = 3
+ * Glyph IDs : 194 48 7 8 4367 1039 1002
+ * Glyph Index: 0 1 2 3 0 1 2
+ *
+ * In this example, the "fi" is converted into ligature form, thus the single glyph ID is
+ * assigned for two characters, f and i.
+ *
+ * Example:
+ * ```
+ * private val glyphFilter: GlyphCallback = { glyph, progress ->
+ * val index = glyph.runStart
+ * val i = glyph.glyphIndex
+ * val moveAmount = 1.3f
+ * val sign = (-1 + 2 * ((i + index) % 2))
+ * val turnProgress = if (progress < .5f) progress / 0.5f else (1.0f - progress) / 0.5f
+ *
+ * // You can modify (x, y) coordinates, textSize and color during animation.
+ * glyph.textSize += glyph.textSize * sign * moveAmount * turnProgress
+ * glyph.y += glyph.y * sign * moveAmount * turnProgress
+ * glyph.x += glyph.x * sign * moveAmount * turnProgress
+ * }
+ * ```
+ */
+ var glyphFilter: GlyphCallback?
+ get() = textInterpolator.glyphFilter
+ set(value) { textInterpolator.glyphFilter = value }
+
fun draw(c: Canvas) = textInterpolator.draw(c)
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
index 5d5797cbbb3d..20dbe29efb35 100644
--- a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
+++ b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
@@ -89,8 +89,11 @@ class TextInterpolator(
private var lines = listOf<Line>()
private val fontInterpolator = FontInterpolator()
- // Recycling object for glyph drawing. Will be extended for the longest font run if needed.
- private val tmpDrawPaint = TextPaint()
+ // Recycling object for glyph drawing and tweaking.
+ private val tmpPaint = TextPaint()
+ private val tmpPaintForGlyph by lazy { TextPaint() }
+ private val tmpGlyph by lazy { MutablePositionedGlyph() }
+ // Will be extended for the longest font run if needed.
private var tmpPositionArray = FloatArray(20)
/**
@@ -206,8 +209,8 @@ class TextInterpolator(
} else if (progress == 1f) {
basePaint.set(targetPaint)
} else {
- lerp(basePaint, targetPaint, progress, tmpDrawPaint)
- basePaint.set(tmpDrawPaint)
+ lerp(basePaint, targetPaint, progress, tmpPaint)
+ basePaint.set(tmpPaint)
}
lines.forEach { line ->
@@ -231,7 +234,7 @@ class TextInterpolator(
* @param canvas a canvas.
*/
fun draw(canvas: Canvas) {
- lerp(basePaint, targetPaint, progress, tmpDrawPaint)
+ lerp(basePaint, targetPaint, progress, tmpPaint)
lines.forEachIndexed { lineNo, line ->
line.runs.forEach { run ->
canvas.save()
@@ -241,7 +244,7 @@ class TextInterpolator(
canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
run.fontRuns.forEach { fontRun ->
- drawFontRun(canvas, run, fontRun, tmpDrawPaint)
+ drawFontRun(canvas, run, fontRun, tmpPaint)
}
} finally {
canvas.restore()
@@ -330,24 +333,82 @@ class TextInterpolator(
}
}
+ private class MutablePositionedGlyph : TextAnimator.PositionedGlyph() {
+ override var runStart: Int = 0
+ public set
+ override var runLength: Int = 0
+ public set
+ override var glyphIndex: Int = 0
+ public set
+ override lateinit var font: Font
+ public set
+ override var glyphId: Int = 0
+ public set
+ }
+
+ var glyphFilter: GlyphCallback? = null
+
// Draws single font run.
private fun drawFontRun(c: Canvas, line: Run, run: FontRun, paint: Paint) {
var arrayIndex = 0
+ val font = fontInterpolator.lerp(run.baseFont, run.targetFont, progress)
+
+ val glyphFilter = glyphFilter
+ if (glyphFilter == null) {
+ for (i in run.start until run.end) {
+ tmpPositionArray[arrayIndex++] =
+ MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ tmpPositionArray[arrayIndex++] =
+ MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ }
+ c.drawGlyphs(line.glyphIds, run.start, tmpPositionArray, 0, run.length, font, paint)
+ return
+ }
+
+ tmpGlyph.font = font
+ tmpGlyph.runStart = run.start
+ tmpGlyph.runLength = run.end - run.start
+
+ tmpPaintForGlyph.set(paint)
+ var prevStart = run.start
+
for (i in run.start until run.end) {
- tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
- tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ tmpGlyph.glyphId = line.glyphIds[i]
+ tmpGlyph.x = MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ tmpGlyph.y = MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ tmpGlyph.textSize = paint.textSize
+ tmpGlyph.color = paint.color
+
+ glyphFilter(tmpGlyph, progress)
+
+ if (tmpGlyph.textSize != paint.textSize || tmpGlyph.color != paint.color) {
+ tmpPaintForGlyph.textSize = tmpGlyph.textSize
+ tmpPaintForGlyph.color = tmpGlyph.color
+
+ c.drawGlyphs(
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ i - prevStart,
+ font,
+ tmpPaintForGlyph)
+ prevStart = i
+ arrayIndex = 0
+ }
+
+ tmpPositionArray[arrayIndex++] = tmpGlyph.x
+ tmpPositionArray[arrayIndex++] = tmpGlyph.y
}
c.drawGlyphs(
line.glyphIds,
- run.start,
+ prevStart,
tmpPositionArray,
0,
- run.length,
- fontInterpolator.lerp(run.baseFont, run.targetFont, progress),
- paint)
+ run.end - prevStart,
+ font,
+ tmpPaintForGlyph)
}
private fun updatePositionsAndFonts(
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 013cdac94ab8..9a0bfc19f848 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -53,8 +53,11 @@ import javax.inject.Inject;
/**
* Manages custom clock faces for AOD and lock screen.
+ *
+ * @deprecated Migrate to ClockRegistry
*/
@SysUISingleton
+@Deprecated
public final class ClockManager {
private static final String TAG = "ClockOptsProvider";
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java
new file mode 100644
index 000000000000..fd84543ee50b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.qs.QSUserSwitcherEvent;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+
+import javax.inject.Inject;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
+/**
+ * Manages handling of guest session persistent notification
+ * and actions to reset guest or exit guest session
+ */
+public final class GuestResetOrExitSessionReceiver extends BroadcastReceiver {
+
+ private static final String TAG = GuestResetOrExitSessionReceiver.class.getSimpleName();
+
+ /**
+ * Broadcast sent to the system when guest user needs to be reset.
+ * This is only sent to registered receivers, not manifest receivers.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_GUEST_RESET = "android.intent.action.GUEST_RESET";
+
+ /**
+ * Broadcast sent to the system when guest user needs to exit.
+ * This is only sent to registered receivers, not manifest receivers.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_GUEST_EXIT = "android.intent.action.GUEST_EXIT";
+
+ public AlertDialog mExitSessionDialog;
+ public AlertDialog mResetSessionDialog;
+ private final UserTracker mUserTracker;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final ResetSessionDialog.Factory mResetSessionDialogFactory;
+ private final ExitSessionDialog.Factory mExitSessionDialogFactory;
+
+ @Inject
+ public GuestResetOrExitSessionReceiver(UserTracker userTracker,
+ BroadcastDispatcher broadcastDispatcher,
+ ResetSessionDialog.Factory resetSessionDialogFactory,
+ ExitSessionDialog.Factory exitSessionDialogFactory) {
+ mUserTracker = userTracker;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mResetSessionDialogFactory = resetSessionDialogFactory;
+ mExitSessionDialogFactory = exitSessionDialogFactory;
+ }
+
+ /**
+ * Register this receiver with the {@link BroadcastDispatcher}
+ */
+ public void register() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_GUEST_RESET);
+ intentFilter.addAction(ACTION_GUEST_EXIT);
+ mBroadcastDispatcher.registerReceiver(this, intentFilter, null /* handler */,
+ UserHandle.SYSTEM);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ cancelResetDialog();
+ cancelExitDialog();
+
+ UserInfo currentUser = mUserTracker.getUserInfo();
+ if (!currentUser.isGuest()) {
+ return;
+ }
+
+ if (ACTION_GUEST_RESET.equals(action)) {
+ mResetSessionDialog = mResetSessionDialogFactory.create(currentUser.id);
+ mResetSessionDialog.show();
+ } else if (ACTION_GUEST_EXIT.equals(action)) {
+ mExitSessionDialog = mExitSessionDialogFactory.create(currentUser.id,
+ currentUser.isEphemeral());
+ mExitSessionDialog.show();
+ }
+ }
+
+ private void cancelResetDialog() {
+ if (mResetSessionDialog != null && mResetSessionDialog.isShowing()) {
+ mResetSessionDialog.cancel();
+ mResetSessionDialog = null;
+ }
+ }
+
+ private void cancelExitDialog() {
+ if (mExitSessionDialog != null && mExitSessionDialog.isShowing()) {
+ mExitSessionDialog.cancel();
+ mExitSessionDialog = null;
+ }
+ }
+
+ /**
+ * Dialog shown when asking for confirmation before
+ * reset and restart of guest user.
+ */
+ public static final class ResetSessionDialog extends SystemUIDialog implements
+ DialogInterface.OnClickListener {
+
+ private final UserSwitcherController mUserSwitcherController;
+ private final UiEventLogger mUiEventLogger;
+ private final int mUserId;
+
+ /** Factory class to create guest reset dialog instance */
+ @AssistedFactory
+ public interface Factory {
+ /** Create a guest reset dialog instance */
+ ResetSessionDialog create(int userId);
+ }
+
+ @AssistedInject
+ ResetSessionDialog(Context context,
+ UserSwitcherController userSwitcherController,
+ UiEventLogger uiEventLogger,
+ @Assisted int userId) {
+ super(context);
+
+ setTitle(com.android.settingslib.R.string.guest_reset_and_restart_dialog_title);
+ setMessage(context.getString(
+ com.android.settingslib.R.string.guest_reset_and_restart_dialog_message));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_reset_guest_confirm_button), this);
+ setCanceledOnTouchOutside(false);
+
+ mUserSwitcherController = userSwitcherController;
+ mUiEventLogger = uiEventLogger;
+ mUserId = userId;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
+ mUserSwitcherController.removeGuestUser(mUserId, UserHandle.USER_NULL);
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ cancel();
+ }
+ }
+ }
+
+ /**
+ * Dialog shown when asking for confirmation before
+ * exit of guest user.
+ */
+ public static final class ExitSessionDialog extends SystemUIDialog implements
+ DialogInterface.OnClickListener {
+
+ private final UserSwitcherController mUserSwitcherController;
+ private final int mUserId;
+ private boolean mIsEphemeral;
+
+ /** Factory class to create guest exit dialog instance */
+ @AssistedFactory
+ public interface Factory {
+ /** Create a guest exit dialog instance */
+ ExitSessionDialog create(int userId, boolean isEphemeral);
+ }
+
+ @AssistedInject
+ ExitSessionDialog(Context context,
+ UserSwitcherController userSwitcherController,
+ @Assisted int userId,
+ @Assisted boolean isEphemeral) {
+ super(context);
+
+ if (isEphemeral) {
+ setTitle(context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_title));
+ setMessage(context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_message));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_button), this);
+ } else {
+ setTitle(context.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_title_non_ephemeral));
+ setMessage(context.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_message_non_ephemeral));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_clear_data_button), this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_save_data_button), this);
+ }
+ setCanceledOnTouchOutside(false);
+
+ mUserSwitcherController = userSwitcherController;
+ mUserId = userId;
+ mIsEphemeral = isEphemeral;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mIsEphemeral) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ // Ephemeral guest: exit guest, guest is removed by the system
+ // on exit, since its marked ephemeral
+ mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, false);
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ // Cancel clicked, do nothing
+ cancel();
+ }
+ } else {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ // Non-ephemeral guest: exit guest, guest is not removed by the system
+ // on exit, since its marked non-ephemeral
+ mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, false);
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ // Non-ephemeral guest: remove guest and then exit
+ mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, true);
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ // Cancel clicked, do nothing
+ cancel();
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 9a6020f8556b..9a8d53228e3f 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -35,12 +35,18 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.settings.SecureSettings;
+import javax.inject.Inject;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
/**
* Manages notification when a guest session is resumed.
*/
public class GuestResumeSessionReceiver extends BroadcastReceiver {
- private static final String TAG = "GuestResumeSessionReceiver";
+ private static final String TAG = GuestResumeSessionReceiver.class.getSimpleName();
@VisibleForTesting
public static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
@@ -48,27 +54,31 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
@VisibleForTesting
public AlertDialog mNewSessionDialog;
private final UserTracker mUserTracker;
- private final UserSwitcherController mUserSwitcherController;
- private final UiEventLogger mUiEventLogger;
private final SecureSettings mSecureSettings;
-
- public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
- UserTracker userTracker, UiEventLogger uiEventLogger,
- SecureSettings secureSettings) {
- mUserSwitcherController = userSwitcherController;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final ResetSessionDialog.Factory mResetSessionDialogFactory;
+ private final GuestSessionNotification mGuestSessionNotification;
+
+ @Inject
+ public GuestResumeSessionReceiver(
+ UserTracker userTracker,
+ SecureSettings secureSettings,
+ BroadcastDispatcher broadcastDispatcher,
+ GuestSessionNotification guestSessionNotification,
+ ResetSessionDialog.Factory resetSessionDialogFactory) {
mUserTracker = userTracker;
- mUiEventLogger = uiEventLogger;
mSecureSettings = secureSettings;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mGuestSessionNotification = guestSessionNotification;
+ mResetSessionDialogFactory = resetSessionDialogFactory;
}
/**
* Register this receiver with the {@link BroadcastDispatcher}
- *
- * @param broadcastDispatcher to register the receiver.
*/
- public void register(BroadcastDispatcher broadcastDispatcher) {
+ public void register() {
IntentFilter f = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- broadcastDispatcher.registerReceiver(this, f, null /* handler */, UserHandle.SYSTEM);
+ mBroadcastDispatcher.registerReceiver(this, f, null /* handler */, UserHandle.SYSTEM);
}
@Override
@@ -89,14 +99,25 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
return;
}
- int notFirstLogin = mSecureSettings.getIntForUser(
+ int guestLoginState = mSecureSettings.getIntForUser(
SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
- if (notFirstLogin != 0) {
- mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
- mUiEventLogger, userId);
+
+ if (guestLoginState == 0) {
+ // set 1 to indicate, 1st login
+ guestLoginState = 1;
+ mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState, userId);
+ } else if (guestLoginState == 1) {
+ // set 2 to indicate, 2nd or later login
+ guestLoginState = 2;
+ mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState, userId);
+ }
+
+ mGuestSessionNotification.createPersistentNotification(currentUser,
+ (guestLoginState <= 1));
+
+ if (guestLoginState > 1) {
+ mNewSessionDialog = mResetSessionDialogFactory.create(userId);
mNewSessionDialog.show();
- } else {
- mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
}
}
}
@@ -124,11 +145,20 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
private final UiEventLogger mUiEventLogger;
private final int mUserId;
- ResetSessionDialog(Context context,
+
+ /** Factory class to create guest reset dialog instance */
+ @AssistedFactory
+ public interface Factory {
+ /** Create a guest reset dialog instance */
+ ResetSessionDialog create(int userId);
+ }
+
+ @AssistedInject
+ public ResetSessionDialog(Context context,
UserSwitcherController userSwitcherController,
UiEventLogger uiEventLogger,
- int userId) {
- super(context, false /* dismissOnDeviceLock */);
+ @Assisted int userId) {
+ super(context, DEFAULT_THEME, false /* dismissOnDeviceLock */);
setTitle(context.getString(R.string.guest_wipe_session_title));
setMessage(context.getString(R.string.guest_wipe_session_message));
diff --git a/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java b/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java
new file mode 100644
index 000000000000..b0eaab97c5ac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.FeatureFlagUtils;
+
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.util.NotificationChannels;
+
+import javax.inject.Inject;
+
+/**
+ * Posts a persistent notification on entry to guest mode
+ */
+public final class GuestSessionNotification {
+
+ private static final String TAG = GuestSessionNotification.class.getSimpleName();
+
+ private final Context mContext;
+ private final NotificationManager mNotificationManager;
+
+ @Inject
+ public GuestSessionNotification(Context context,
+ NotificationManager notificationManager) {
+ mContext = context;
+ mNotificationManager = notificationManager;
+ }
+
+ private void overrideNotificationAppName(Notification.Builder notificationBuilder) {
+ final Bundle extras = new Bundle();
+ String appName = mContext.getString(R.string.guest_notification_app_name);
+
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName);
+
+ notificationBuilder.addExtras(extras);
+ }
+
+ void createPersistentNotification(UserInfo userInfo, boolean isGuestFirstLogin) {
+ if (!FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_GUEST_MODE_UX_CHANGES)
+ || !userInfo.isGuest()) {
+ // we create a persistent notification only if enabled and only for guests
+ return;
+ }
+ String contentText;
+ if (userInfo.isEphemeral()) {
+ contentText = mContext.getString(R.string.guest_notification_ephemeral);
+ } else if (isGuestFirstLogin) {
+ contentText = mContext.getString(R.string.guest_notification_non_ephemeral);
+ } else {
+ contentText = mContext.getString(
+ R.string.guest_notification_non_ephemeral_non_first_login);
+ }
+
+ final Intent guestExitIntent = new Intent(
+ GuestResetOrExitSessionReceiver.ACTION_GUEST_EXIT);
+ final Intent userSettingsIntent = new Intent(Settings.ACTION_USER_SETTINGS);
+
+ PendingIntent guestExitPendingIntent =
+ PendingIntent.getBroadcastAsUser(mContext, 0, guestExitIntent,
+ PendingIntent.FLAG_IMMUTABLE,
+ UserHandle.SYSTEM);
+
+ PendingIntent userSettingsPendingIntent =
+ PendingIntent.getActivityAsUser(mContext, 0, userSettingsIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+ null,
+ UserHandle.of(userInfo.id));
+
+ Notification.Builder builder = new Notification.Builder(mContext,
+ NotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.ic_account_circle)
+ .setContentTitle(mContext.getString(R.string.guest_notification_session_active))
+ .setContentText(contentText)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setOngoing(true)
+ .setContentIntent(userSettingsPendingIntent);
+
+ // we show reset button only if this is a 2nd or later login
+ if (!isGuestFirstLogin) {
+ final Intent guestResetIntent = new Intent(
+ GuestResetOrExitSessionReceiver.ACTION_GUEST_RESET);
+
+ PendingIntent guestResetPendingIntent =
+ PendingIntent.getBroadcastAsUser(mContext, 0, guestResetIntent,
+ PendingIntent.FLAG_IMMUTABLE,
+ UserHandle.SYSTEM);
+
+ builder.addAction(R.drawable.ic_sysbar_home,
+ mContext.getString(
+ com.android.settingslib.R.string.guest_reset_guest_confirm_button),
+ guestResetPendingIntent);
+ }
+ builder.addAction(R.drawable.ic_sysbar_home,
+ mContext.getString(
+ com.android.settingslib.R.string.guest_exit_button),
+ guestExitPendingIntent);
+
+ overrideNotificationAppName(builder);
+
+ mNotificationManager.notifyAsUser(null,
+ SystemMessageProto.SystemMessage.NOTE_GUEST_SESSION,
+ builder.build(),
+ UserHandle.of(userInfo.id));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index f5084f5cff76..2dade21caca7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -29,9 +29,9 @@ import com.android.systemui.dagger.DaggerGlobalRootComponent;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
-import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
+import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Map;
@@ -114,13 +114,11 @@ public class SystemUIFactory {
// components that shouldn't be run in the test environment
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(mWMComponent.getPip())
- .setLegacySplitScreen(mWMComponent.getLegacySplitScreen())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
.setBubbles(mWMComponent.getBubbles())
.setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
- .setAppPairs(mWMComponent.getAppPairs())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
.setTransitions(mWMComponent.getTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
@@ -135,13 +133,11 @@ public class SystemUIFactory {
// is separating this logic into newly creating SystemUITestsFactory.
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(Optional.ofNullable(null))
- .setLegacySplitScreen(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
.setBubbles(Optional.ofNullable(null))
.setHideDisplayCutout(Optional.ofNullable(null))
.setShellCommandHandler(Optional.ofNullable(null))
- .setAppPairs(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(new ShellTransitions() {})
.setDisplayAreaHelper(Optional.ofNullable(null))
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index bd8e44ceab80..448b99b6e5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -199,8 +199,9 @@ public class SystemActions extends CoreStartable {
mNotificationShadeController = notificationShadeController;
// Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references.
- mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing) ->
- registerOrUnregisterDismissNotificationShadeAction();
+ mNotificationShadeCallback =
+ (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) ->
+ registerOrUnregisterDismissNotificationShadeAction();
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 6e14ddc671a3..d7fead16e269 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -28,6 +28,7 @@ import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.view.Display;
import android.view.SurfaceControl;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -89,9 +90,14 @@ public class WindowMagnification extends CoreStartable implements WindowMagnifie
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
return new WindowMagnificationController(
windowContext,
- mHandler, new WindowMagnificationAnimationController(windowContext),
- new SfVsyncFrameCallbackProvider(), null,
- new SurfaceControl.Transaction(), mWindowMagnifierCallback, mSysUiState);
+ mHandler,
+ new WindowMagnificationAnimationController(windowContext),
+ new SfVsyncFrameCallbackProvider(),
+ null,
+ new SurfaceControl.Transaction(),
+ mWindowMagnifierCallback,
+ mSysUiState,
+ WindowManagerGlobal::getWindowSession);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index a1428f3120c8..1eedae6f01b0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -57,11 +57,11 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import android.widget.FrameLayout;
import androidx.core.math.MathUtils;
@@ -75,6 +75,7 @@ import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Locale;
+import java.util.function.Supplier;
/**
* Class to handle adding and removing a window magnification.
@@ -92,6 +93,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private static final Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(2.0f, 8.0f);
private static final float A11Y_CHANGE_SCALE_DIFFERENCE = 1.0f;
private static final float ANIMATION_BOUNCE_EFFECT_SCALE = 1.05f;
+
private final Context mContext;
private final Resources mResources;
private final Handler mHandler;
@@ -163,8 +165,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private SurfaceView mMirrorSurfaceView;
private int mMirrorSurfaceMargin;
private int mBorderDragSize;
- private int mDragViewSize;
private int mOuterBorderSize;
+
+ /**
+ * How far from the right edge of the screen you need to drag the window before the button
+ * repositions to the other side.
+ */
+ private int mButtonRepositionThresholdFromEdge;
// The boundary of magnification frame.
private final Rect mMagnificationFrameBoundary = new Rect();
// The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
@@ -172,6 +179,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private int mMinWindowSize;
private final WindowMagnificationAnimationController mAnimationController;
+ private final Supplier<IWindowSession> mGlobalWindowSessionSupplier;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
private final MagnificationGestureDetector mGestureDetector;
private final int mBounceEffectDuration;
@@ -182,18 +190,25 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private SysUiState mSysUiState;
// Set it to true when the view is overlapped with the gesture insets at the bottom.
private boolean mOverlapWithGestureInsets;
+ private boolean mIsDragging;
@Nullable
private MirrorWindowControl mMirrorWindowControl;
- WindowMagnificationController(@UiContext Context context, @NonNull Handler handler,
+ WindowMagnificationController(
+ @UiContext Context context,
+ @NonNull Handler handler,
@NonNull WindowMagnificationAnimationController animationController,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
- MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
- @NonNull WindowMagnifierCallback callback, SysUiState sysUiState) {
+ MirrorWindowControl mirrorWindowControl,
+ SurfaceControl.Transaction transaction,
+ @NonNull WindowMagnifierCallback callback,
+ SysUiState sysUiState,
+ @NonNull Supplier<IWindowSession> globalWindowSessionSupplier) {
mContext = context;
mHandler = handler;
mAnimationController = animationController;
+ mGlobalWindowSessionSupplier = globalWindowSessionSupplier;
mAnimationController.setWindowMagnificationController(this);
mSfVsyncFrameProvider = sfVsyncFrameProvider;
mWindowMagnifierCallback = callback;
@@ -249,8 +264,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
};
mMirrorSurfaceViewLayoutChangeListener =
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
- -> applyTapExcludeRegion();
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+ mMirrorView.post(this::applyTapExcludeRegion);
mMirrorViewGeometryVsyncCallback =
l -> {
@@ -283,10 +298,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
R.dimen.magnification_mirror_surface_margin);
mBorderDragSize = mResources.getDimensionPixelSize(
R.dimen.magnification_border_drag_size);
- mDragViewSize = mResources.getDimensionPixelSize(
- R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin);
+ mButtonRepositionThresholdFromEdge =
+ mResources.getDimensionPixelSize(
+ R.dimen.magnification_button_reposition_threshold_from_edge);
mMinWindowSize = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
}
@@ -551,10 +567,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
private void applyTapExcludeRegion() {
+ // Sometimes this can get posted and run after deleteWindowMagnification() is called.
+ if (mMirrorView == null) return;
+
final Region tapExcludeRegion = calculateTapExclude();
final IWindow window = IWindow.Stub.asInterface(mMirrorView.getWindowToken());
try {
- IWindowSession session = WindowManagerGlobal.getWindowSession();
+ IWindowSession session = mGlobalWindowSessionSupplier.get();
session.updateTapExcludeRegion(window, tapExcludeRegion);
} catch (RemoteException e) {
}
@@ -564,9 +583,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
Region regionInsideDragBorder = new Region(mBorderDragSize, mBorderDragSize,
mMirrorView.getWidth() - mBorderDragSize,
mMirrorView.getHeight() - mBorderDragSize);
- Rect dragArea = new Rect(mMirrorView.getWidth() - mDragViewSize - mBorderDragSize,
- mMirrorView.getHeight() - mDragViewSize - mBorderDragSize,
- mMirrorView.getWidth(), mMirrorView.getHeight());
+ Rect dragArea = new Rect();
+ mDragView.getHitRect(dragArea);
+
regionInsideDragBorder.op(dragArea, Region.Op.DIFFERENCE);
return regionInsideDragBorder;
}
@@ -713,6 +732,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mMirrorView.setTranslationX(translationX);
mMirrorView.setTranslationY(translationY);
mWm.updateViewLayout(mMirrorView, params);
+
+ // If they are not dragging the handle, we can move the drag handle immediately without
+ // disruption. But if they are dragging it, we avoid moving until the end of the drag.
+ if (!mIsDragging) {
+ mMirrorView.post(this::maybeRepositionButton);
+ }
}
@Override
@@ -1060,14 +1085,40 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
@Override
public boolean onStart(float x, float y) {
+ mIsDragging = true;
return true;
}
@Override
public boolean onFinish(float x, float y) {
+ maybeRepositionButton();
+ mIsDragging = false;
return false;
}
+ /** Moves the button to the opposite edge if the frame is against the edge of the screen. */
+ private void maybeRepositionButton() {
+ if (mMirrorView == null) return;
+
+ final float screenEdgeX = mWindowBounds.right - mButtonRepositionThresholdFromEdge;
+ final FrameLayout.LayoutParams layoutParams =
+ (FrameLayout.LayoutParams) mDragView.getLayoutParams();
+
+ mMirrorView.getBoundsOnScreen(mTmpRect);
+
+ final int newGravity;
+ if (mTmpRect.right >= screenEdgeX) {
+ newGravity = Gravity.BOTTOM | Gravity.LEFT;
+ } else {
+ newGravity = Gravity.BOTTOM | Gravity.RIGHT;
+ }
+ if (newGravity != layoutParams.gravity) {
+ layoutParams.gravity = newGravity;
+ mDragView.setLayoutParams(layoutParams);
+ mDragView.post(this::applyTapExcludeRegion);
+ }
+ }
+
private void animateBounceEffect() {
final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView,
PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index cd16379cd5b4..606a73a6ac38 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -36,12 +36,20 @@ open class AuthBiometricFingerprintIconController(
iconView: ImageView
) : AuthIconController(context, iconView) {
+ var iconLayoutParamsSize = 0
+ set(value) {
+ if (field == value) {
+ return
+ }
+ iconView.layoutParams.width = value
+ iconView.layoutParams.height = value
+ field = value
+ }
+
init {
- val size = context.resources.getDimensionPixelSize(
+ iconLayoutParamsSize = context.resources.getDimensionPixelSize(
R.dimen.biometric_dialog_fingerprint_icon_size
)
- iconView.layoutParams.width = size
- iconView.layoutParams.height = size
}
override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 368bc3aadb70..24046f08e489 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -22,6 +22,7 @@ import android.util.Log
import android.widget.FrameLayout
import android.widget.TextView
import com.android.systemui.R
+import com.android.systemui.biometrics.AuthController.ScaleFactorProvider
private const val TAG = "AuthBiometricFingerprintView"
@@ -35,6 +36,7 @@ open class AuthBiometricFingerprintView(
private set
private var udfpsAdapter: UdfpsDialogMeasureAdapter? = null
+ private var scaleFactorProvider: ScaleFactorProvider? = null
/** Set the [sensorProps] of this sensor so the view can be customized prior to layout. */
fun setSensorProperties(sensorProps: FingerprintSensorPropertiesInternal) {
@@ -42,9 +44,15 @@ open class AuthBiometricFingerprintView(
udfpsAdapter = if (isUdfps) UdfpsDialogMeasureAdapter(this, sensorProps) else null
}
+ fun setScaleFactorProvider(scaleProvider: ScaleFactorProvider?) {
+ scaleFactorProvider = scaleProvider
+ }
+
override fun onMeasureInternal(width: Int, height: Int): AuthDialog.LayoutParams {
val layoutParams = super.onMeasureInternal(width, height)
- return udfpsAdapter?.onMeasureInternal(width, height, layoutParams) ?: layoutParams
+ val scale = scaleFactorProvider?.provide() ?: 1.0f
+ return udfpsAdapter?.onMeasureInternal(width, height, layoutParams,
+ scale) ?: layoutParams
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
@@ -80,6 +88,13 @@ open class AuthBiometricFingerprintView(
override fun createIconController(): AuthIconController =
AuthBiometricFingerprintIconController(mContext, mIconView)
+ fun updateOverrideIconLayoutParamsSize() {
+ udfpsAdapter?.let {
+ (mIconController as? AuthBiometricFingerprintIconController)?.iconLayoutParamsSize =
+ it.getSensorDiameter(scaleFactorProvider?.provide() ?: 1.0f)
+ }
+ }
+
override fun onAttachedToWindow() {
super.onAttachedToWindow()
showTouchSensorString()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 1413f4a81574..d7ae9ef841bf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -59,7 +59,7 @@ import java.util.Set;
/**
* Contains the Biometric views (title, subtitle, icon, buttons, etc.) and its controllers.
*/
-public class AuthBiometricView extends LinearLayout {
+public abstract class AuthBiometricView extends LinearLayout {
private static final String TAG = "AuthBiometricView";
@@ -116,7 +116,7 @@ public class AuthBiometricView extends LinearLayout {
void onAction(int action);
}
- protected final Handler mHandler;
+ private final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
private final LockPatternUtils mLockPatternUtils;
protected final int mTextColorError;
@@ -155,8 +155,8 @@ public class AuthBiometricView extends LinearLayout {
// Measurements when biometric view is showing text, buttons, etc.
@Nullable @VisibleForTesting AuthDialog.LayoutParams mLayoutParams;
- protected Callback mCallback;
- protected @BiometricState int mState;
+ private Callback mCallback;
+ @BiometricState private int mState;
private float mIconOriginalY;
@@ -166,6 +166,8 @@ public class AuthBiometricView extends LinearLayout {
private final Runnable mResetErrorRunnable;
private final Runnable mResetHelpRunnable;
+ private Animator.AnimatorListener mJankListener;
+
private final OnClickListener mBackgroundClickListener = (view) -> {
if (mState == STATE_AUTHENTICATED) {
Log.w(TAG, "Ignoring background click after authenticated");
@@ -250,18 +252,9 @@ public class AuthBiometricView extends LinearLayout {
return false;
}
- /**
- * Create the controller for managing the icons transitions during the prompt.
- *
- * Subclass should override.
- */
+ /** Create the controller for managing the icons transitions during the prompt.*/
@NonNull
- protected AuthIconController createIconController() {
- return new AuthIconController(mContext, mIconView) {
- @Override
- public void updateIcon(int lastState, int newState) {}
- };
- }
+ protected abstract AuthIconController createIconController();
void setPanelController(AuthPanelController panelController) {
mPanelController = panelController;
@@ -291,6 +284,10 @@ public class AuthBiometricView extends LinearLayout {
mRequireConfirmation = requireConfirmation && supportsRequireConfirmation();
}
+ void setJankListener(Animator.AnimatorListener jankListener) {
+ mJankListener = jankListener;
+ }
+
@VisibleForTesting
final void updateSize(@AuthDialog.DialogSize int newSize) {
Log.v(TAG, "Current size: " + mSize + " New size: " + newSize);
@@ -381,6 +378,9 @@ public class AuthBiometricView extends LinearLayout {
}
});
+ if (mJankListener != null) {
+ as.addListener(mJankListener);
+ }
as.play(iconAnimator).with(opacityAnimator);
as.start();
// Animate the panel
@@ -436,6 +436,9 @@ public class AuthBiometricView extends LinearLayout {
animators.add(translationAnimator);
animators.add(opacityAnimator);
+ if (mJankListener != null) {
+ as.addListener(mJankListener);
+ }
as.playTogether(animators);
as.setDuration(mAnimationDurationLong * 2 / 3);
as.start();
@@ -881,4 +884,14 @@ public class AuthBiometricView extends LinearLayout {
@AuthDialog.DialogSize int getSize() {
return mSize;
}
+
+ /** If authentication has successfully occurred and the view is done. */
+ boolean isAuthenticated() {
+ return mState == STATE_AUTHENTICATED;
+ }
+
+ /** If authentication is currently in progress. */
+ boolean isAuthenticating() {
+ return mState == STATE_AUTHENTICATING;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 233f3648aeb3..4ffea14a62b4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -19,6 +19,9 @@ package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
+
+import android.animation.Animator;
import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -53,13 +56,16 @@ import android.widget.LinearLayout;
import android.widget.ScrollView;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
@@ -84,6 +90,13 @@ public class AuthContainerView extends LinearLayout
private static final int STATE_ANIMATING_OUT = 4;
private static final int STATE_GONE = 5;
+ /** Shows biometric prompt dialog animation. */
+ private static final String SHOW = "show";
+ /** Dismiss biometric prompt dialog animation. */
+ private static final String DISMISS = "dismiss";
+ /** Transit biometric prompt dialog to pin, password, pattern credential panel. */
+ private static final String TRANSIT = "transit";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_UNKNOWN, STATE_ANIMATING_IN, STATE_PENDING_DISMISS, STATE_SHOWING,
STATE_ANIMATING_OUT, STATE_GONE})
@@ -98,6 +111,7 @@ public class AuthContainerView extends LinearLayout
private final CredentialCallback mCredentialCallback;
private final LockPatternUtils mLockPatternUtils;
private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final InteractionJankMonitor mInteractionJankMonitor;
@VisibleForTesting final BiometricCallback mBiometricCallback;
@@ -133,6 +147,7 @@ public class AuthContainerView extends LinearLayout
long mRequestId = -1;
boolean mSkipAnimation = false;
@BiometricMultiSensorMode int mMultiSensorConfig = BIOMETRIC_MULTI_SENSOR_DEFAULT;
+ ScaleFactorProvider mScaleProvider;
}
public static class Builder {
@@ -196,15 +211,22 @@ public class AuthContainerView extends LinearLayout
return this;
}
+ public Builder setScaleFactorProvider(ScaleFactorProvider scaleProvider) {
+ mConfig.mScaleProvider = scaleProvider;
+ return this;
+ }
+
public AuthContainerView build(@Background DelayableExecutor bgExecutor, int[] sensorIds,
@Nullable List<FingerprintSensorPropertiesInternal> fpProps,
@Nullable List<FaceSensorPropertiesInternal> faceProps,
@NonNull WakefulnessLifecycle wakefulnessLifecycle,
@NonNull UserManager userManager,
- @NonNull LockPatternUtils lockPatternUtils) {
+ @NonNull LockPatternUtils lockPatternUtils,
+ @NonNull InteractionJankMonitor jankMonitor) {
mConfig.mSensorIds = sensorIds;
return new AuthContainerView(mConfig, fpProps, faceProps, wakefulnessLifecycle,
- userManager, lockPatternUtils, new Handler(Looper.getMainLooper()), bgExecutor);
+ userManager, lockPatternUtils, jankMonitor, new Handler(Looper.getMainLooper()),
+ bgExecutor);
}
}
@@ -257,6 +279,7 @@ public class AuthContainerView extends LinearLayout
@NonNull WakefulnessLifecycle wakefulnessLifecycle,
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
+ @NonNull InteractionJankMonitor jankMonitor,
@NonNull Handler mainHandler,
@NonNull @Background DelayableExecutor bgExecutor) {
super(config.mContext);
@@ -283,6 +306,7 @@ public class AuthContainerView extends LinearLayout
mPanelView = mFrameLayout.findViewById(R.id.panel);
mPanelController = new AuthPanelController(mContext, mPanelView);
mBackgroundExecutor = bgExecutor;
+ mInteractionJankMonitor = jankMonitor;
// Inflate biometric view only if necessary.
if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
@@ -296,12 +320,16 @@ public class AuthContainerView extends LinearLayout
(AuthBiometricFingerprintAndFaceView) layoutInflater.inflate(
R.layout.auth_biometric_fingerprint_and_face_view, null, false);
fingerprintAndFaceView.setSensorProperties(fpProperties);
+ fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
+ fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =
(AuthBiometricFingerprintView) layoutInflater.inflate(
R.layout.auth_biometric_fingerprint_view, null, false);
fpView.setSensorProperties(fpProperties);
+ fpView.setScaleFactorProvider(config.mScaleProvider);
+ fpView.updateOverrideIconLayoutParamsSize();
mBiometricView = fpView;
} else if (faceProperties != null) {
mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
@@ -320,6 +348,8 @@ public class AuthContainerView extends LinearLayout
mBiometricView.setBackgroundView(mBackgroundView);
mBiometricView.setUserId(mConfig.mUserId);
mBiometricView.setEffectiveUserId(mEffectiveUserId);
+ mBiometricView.setJankListener(getJankListener(mBiometricView, TRANSIT,
+ AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS));
}
// TODO: De-dupe the logic with AuthCredentialPasswordView
@@ -438,6 +468,7 @@ public class AuthContainerView extends LinearLayout
.translationY(0)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mPanelView, SHOW, animateDuration))
.withLayer()
.withEndAction(this::onDialogAnimatedIn)
.start();
@@ -445,6 +476,7 @@ public class AuthContainerView extends LinearLayout
.translationY(0)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mBiometricScrollView, SHOW, animateDuration))
.withLayer()
.start();
if (mCredentialView != null && mCredentialView.isAttachedToWindow()) {
@@ -453,6 +485,7 @@ public class AuthContainerView extends LinearLayout
.translationY(0)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mCredentialView, SHOW, animateDuration))
.withLayer()
.start();
}
@@ -461,11 +494,49 @@ public class AuthContainerView extends LinearLayout
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
.withLayer()
+ .setListener(getJankListener(this, SHOW, animateDuration))
.start();
});
}
}
+ private Animator.AnimatorListener getJankListener(View v, String type, long timeout) {
+ return new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(@androidx.annotation.NonNull Animator animation) {
+ if (!v.isAttachedToWindow()) {
+ Log.w(TAG, "Un-attached view should not begin Jank trace.");
+ return;
+ }
+ mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder.withView(
+ CUJ_BIOMETRIC_PROMPT_TRANSITION, v).setTag(type).setTimeout(timeout));
+ }
+
+ @Override
+ public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) {
+ if (!v.isAttachedToWindow()) {
+ Log.w(TAG, "Un-attached view should not end Jank trace.");
+ return;
+ }
+ mInteractionJankMonitor.end(CUJ_BIOMETRIC_PROMPT_TRANSITION);
+ }
+
+ @Override
+ public void onAnimationCancel(@androidx.annotation.NonNull Animator animation) {
+ if (!v.isAttachedToWindow()) {
+ Log.w(TAG, "Un-attached view should not cancel Jank trace.");
+ return;
+ }
+ mInteractionJankMonitor.cancel(CUJ_BIOMETRIC_PROMPT_TRANSITION);
+ }
+
+ @Override
+ public void onAnimationRepeat(@androidx.annotation.NonNull Animator animation) {
+ // no-op
+ }
+ };
+ }
+
private static boolean shouldUpdatePositionForUdfps(@NonNull View view) {
if (view instanceof AuthBiometricFingerprintView) {
return ((AuthBiometricFingerprintView) view).isUdfps();
@@ -649,6 +720,7 @@ public class AuthContainerView extends LinearLayout
.translationY(mTranslationY)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mPanelView, DISMISS, animateDuration))
.withLayer()
.withEndAction(endActionRunnable)
.start();
@@ -656,6 +728,7 @@ public class AuthContainerView extends LinearLayout
.translationY(mTranslationY)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mBiometricScrollView, DISMISS, animateDuration))
.withLayer()
.start();
if (mCredentialView != null && mCredentialView.isAttachedToWindow()) {
@@ -663,6 +736,7 @@ public class AuthContainerView extends LinearLayout
.translationY(mTranslationY)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(mCredentialView, DISMISS, animateDuration))
.withLayer()
.start();
}
@@ -670,6 +744,7 @@ public class AuthContainerView extends LinearLayout
.alpha(0f)
.setDuration(animateDuration)
.setInterpolator(mLinearOutSlowIn)
+ .setListener(getJankListener(this, DISMISS, animateDuration))
.withLayer()
.start();
});
@@ -730,4 +805,36 @@ public class AuthContainerView extends LinearLayout
lp.token = windowToken;
return lp;
}
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println(" isAttachedToWindow=" + isAttachedToWindow());
+ pw.println(" containerState=" + mContainerState);
+ pw.println(" pendingCallbackReason=" + mPendingCallbackReason);
+ pw.println(" config exist=" + (mConfig != null));
+ if (mConfig != null) {
+ pw.println(" config.sensorIds exist=" + (mConfig.mSensorIds != null));
+ }
+ final AuthBiometricView biometricView = mBiometricView;
+ pw.println(" scrollView=" + findViewById(R.id.biometric_scrollview));
+ pw.println(" biometricView=" + biometricView);
+ if (biometricView != null) {
+ int[] ids = {
+ R.id.title,
+ R.id.subtitle,
+ R.id.description,
+ R.id.biometric_icon_frame,
+ R.id.biometric_icon,
+ R.id.indicator,
+ R.id.button_bar,
+ R.id.button_negative,
+ R.id.button_use_credential,
+ R.id.button_confirm,
+ R.id.button_try_again
+ };
+ for (final int id: ids) {
+ pw.println(" " + biometricView.findViewById(id));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 17396469c10a..41aa112d5c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -62,6 +62,7 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.os.SomeArgs;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.CoreStartable;
@@ -75,6 +76,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -143,6 +145,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
private boolean mAllFingerprintAuthenticatorsRegistered;
@NonNull private final UserManager mUserManager;
@NonNull private final LockPatternUtils mLockPatternUtils;
+ @NonNull private final InteractionJankMonitor mInteractionJankMonitor;
private final @Background DelayableExecutor mBackgroundExecutor;
@VisibleForTesting
@@ -549,6 +552,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull StatusBarStateController statusBarStateController,
+ @NonNull InteractionJankMonitor jankMonitor,
@Main Handler handler,
@Background DelayableExecutor bgExecutor) {
super(context);
@@ -566,6 +570,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
mSidefpsControllerFactory = sidefpsControllerFactory;
mDisplayManager = displayManager;
mWindowManager = windowManager;
+ mInteractionJankMonitor = jankMonitor;
mUdfpsEnrolledForUser = new SparseBooleanArray();
mOrientationListener = new BiometricDisplayListener(
@@ -1037,8 +1042,36 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
.setOperationId(operationId)
.setRequestId(requestId)
.setMultiSensorConfig(multiSensorConfig)
+ .setScaleFactorProvider(() -> {
+ return getScaleFactor();
+ })
.build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle,
- userManager, lockPatternUtils);
+ userManager, lockPatternUtils, mInteractionJankMonitor);
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ final AuthDialog dialog = mCurrentDialog;
+ pw.println(" stableDisplaySize=" + mStableDisplaySize);
+ pw.println(" faceAuthSensorLocation=" + mFaceAuthSensorLocation);
+ pw.println(" fingerprintLocation=" + mFingerprintLocation);
+ pw.println(" udfpsBounds=" + mUdfpsBounds);
+ pw.println(" allFingerprintAuthenticatorsRegistered="
+ + mAllFingerprintAuthenticatorsRegistered);
+ pw.println(" currentDialog=" + dialog);
+ if (dialog != null) {
+ dialog.dump(pw, args);
+ }
+ }
+
+ /**
+ * Provides a float that represents the resolution scale(if the controller is for UDFPS).
+ */
+ public interface ScaleFactorProvider {
+ /**
+ * Returns a float representing the scaled resolution(if the controller if for UDFPS).
+ */
+ float provide();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 4ff19f6adc11..51f39b358659 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -23,13 +23,15 @@ import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Bundle;
import android.view.WindowManager;
+import com.android.systemui.Dumpable;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Interface for the biometric dialog UI.
*/
-public interface AuthDialog {
+public interface AuthDialog extends Dumpable {
String KEY_CONTAINER_GOING_AWAY = "container_going_away";
String KEY_BIOMETRIC_SHOWING = "biometric_showing";
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 86e501670440..38fab8ffbfad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -23,7 +23,6 @@ import android.content.Context
import android.graphics.PointF
import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.biometrics.BiometricSourceType
-import android.util.DisplayMetrics
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
@@ -46,7 +45,6 @@ import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.Cent
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ViewController
-import com.android.systemui.util.leak.RotationUtils
import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Provider
@@ -127,17 +125,37 @@ class AuthRippleController @Inject constructor(
}
updateSensorLocation()
- if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
- fingerprintSensorLocation != null) {
- mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius)
- showUnlockedRipple()
- } else if (biometricSourceType == BiometricSourceType.FACE &&
- faceSensorLocation != null) {
- if (!bypassController.canBypass()) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ fingerprintSensorLocation?.let {
+ mView.setFingerprintSensorLocation(it, udfpsRadius)
+ circleReveal = CircleReveal(
+ it.x,
+ it.y,
+ 0f,
+ Math.max(
+ Math.max(it.x, centralSurfaces.displayWidth - it.x),
+ Math.max(it.y, centralSurfaces.displayHeight - it.y)
+ )
+ )
+ showUnlockedRipple()
+ }
+ } else if (biometricSourceType == BiometricSourceType.FACE) {
+ if (!bypassController.canBypass() && !authController.isUdfpsFingerDown) {
return
}
- mView.setSensorLocation(faceSensorLocation!!)
- showUnlockedRipple()
+ faceSensorLocation?.let {
+ mView.setSensorLocation(it)
+ circleReveal = CircleReveal(
+ it.x,
+ it.y,
+ 0f,
+ Math.max(
+ Math.max(it.x, centralSurfaces.displayWidth - it.x),
+ Math.max(it.y, centralSurfaces.displayHeight - it.y)
+ )
+ )
+ showUnlockedRipple()
+ }
}
}
@@ -209,48 +227,8 @@ class AuthRippleController @Inject constructor(
}
fun updateSensorLocation() {
- updateFingerprintLocation()
+ fingerprintSensorLocation = authController.fingerprintSensorLocation
faceSensorLocation = authController.faceAuthSensorLocation
- fingerprintSensorLocation?.let {
- circleReveal = CircleReveal(
- it.x,
- it.y,
- 0f,
- Math.max(
- Math.max(it.x, centralSurfaces.displayWidth - it.x),
- Math.max(it.y, centralSurfaces.displayHeight - it.y)
- )
- )
- }
- }
-
- private fun updateFingerprintLocation() {
- val displayMetrics = DisplayMetrics()
- sysuiContext.display?.getRealMetrics(displayMetrics)
- val width = displayMetrics.widthPixels
- val height = displayMetrics.heightPixels
-
- authController.fingerprintSensorLocation?.let {
- fingerprintSensorLocation = when (RotationUtils.getRotation(sysuiContext)) {
- RotationUtils.ROTATION_LANDSCAPE -> {
- val normalizedYPos: Float = it.y / width
- val normalizedXPos: Float = it.x / height
- PointF(width * normalizedYPos, height * (1 - normalizedXPos))
- }
- RotationUtils.ROTATION_UPSIDE_DOWN -> {
- PointF(width - it.x, height - it.y)
- }
- RotationUtils.ROTATION_SEASCAPE -> {
- val normalizedYPos: Float = it.y / width
- val normalizedXPos: Float = it.x / height
- PointF(width * (1 - normalizedYPos), height * normalizedXPos)
- }
- else -> {
- // ROTATION_NONE
- PointF(it.x, it.y)
- }
- }
- }
}
private fun updateRippleColor() {
@@ -372,6 +350,7 @@ class AuthRippleController @Inject constructor(
showUnlockRipple(BiometricSourceType.FINGERPRINT)
}
"face" -> {
+ // note: only shows when about to proceed to the home screen
updateSensorLocation()
pw.println("face ripple sensorLocation=$faceSensorLocation")
showUnlockRipple(BiometricSourceType.FACE)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 903b3de0f444..7775f50cdfa3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -845,6 +845,11 @@ public class UdfpsController implements DozeReceiver {
mBiometricExecutor.execute(() -> {
mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major);
});
+ mFgExecutor.execute(() -> {
+ if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
+ mKeyguardUpdateMonitor.onUdfpsPointerDown((int) requestId);
+ }
+ });
} else {
mFingerprintManager.onPointerDown(requestId, mSensorId, x, y, minor, major);
}
@@ -860,7 +865,6 @@ public class UdfpsController implements DozeReceiver {
} else {
mFingerprintManager.onUiReady(requestId, mSensorId);
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
-
}
});
}
@@ -879,6 +883,11 @@ public class UdfpsController implements DozeReceiver {
mBiometricExecutor.execute(() -> {
mAlternateTouchProvider.onPointerUp(requestId);
});
+ mFgExecutor.execute(() -> {
+ if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
+ mKeyguardUpdateMonitor.onUdfpsPointerUp((int) requestId);
+ }
+ });
} else {
mFingerprintManager.onPointerUp(requestId, mSensorId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 8de721352069..43745bf74aae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -64,15 +64,16 @@ public class UdfpsDialogMeasureAdapter {
@NonNull
AuthDialog.LayoutParams onMeasureInternal(
- int width, int height, @NonNull AuthDialog.LayoutParams layoutParams) {
+ int width, int height, @NonNull AuthDialog.LayoutParams layoutParams,
+ float scaleFactor) {
final int displayRotation = mView.getDisplay().getRotation();
switch (displayRotation) {
case Surface.ROTATION_0:
- return onMeasureInternalPortrait(width, height);
+ return onMeasureInternalPortrait(width, height, scaleFactor);
case Surface.ROTATION_90:
case Surface.ROTATION_270:
- return onMeasureInternalLandscape(width, height);
+ return onMeasureInternalLandscape(width, height, scaleFactor);
default:
Log.e(TAG, "Unsupported display rotation: " + displayRotation);
return layoutParams;
@@ -89,8 +90,16 @@ public class UdfpsDialogMeasureAdapter {
return mBottomSpacerHeight;
}
+ /**
+ * @return sensor diameter size as scaleFactor
+ */
+ public int getSensorDiameter(float scaleFactor) {
+ return (int) (scaleFactor * mSensorProps.getLocation().sensorRadius * 2);
+ }
+
@NonNull
- private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) {
+ private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height,
+ float scaleFactor) {
final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
// Figure out where the bottom of the sensor anim should be.
@@ -101,12 +110,12 @@ public class UdfpsDialogMeasureAdapter {
final Insets navbarInsets = getNavbarInsets(windowMetrics);
mBottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight,
- dialogMargin, navbarInsets.bottom);
+ dialogMargin, navbarInsets.bottom, scaleFactor);
// Go through each of the children and do the custom measurement.
int totalHeight = 0;
final int numChildren = mView.getChildCount();
- final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
+ final int sensorDiameter = getSensorDiameter(scaleFactor);
for (int i = 0; i < numChildren; i++) {
final View child = mView.getChildAt(i);
if (child.getId() == R.id.biometric_icon_frame) {
@@ -176,7 +185,8 @@ public class UdfpsDialogMeasureAdapter {
}
@NonNull
- private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) {
+ private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height,
+ float scaleFactor) {
final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
// Find the spacer height needed to vertically align the icon with the sensor.
@@ -197,9 +207,9 @@ public class UdfpsDialogMeasureAdapter {
final int dialogMargin = getDialogMarginPx();
final int horizontalInset = navbarInsets.left + navbarInsets.right;
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
- mSensorProps, displayWidth, dialogMargin, horizontalInset);
+ mSensorProps, displayWidth, dialogMargin, horizontalInset, scaleFactor);
- final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
+ final int sensorDiameter = getSensorDiameter(scaleFactor);
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
int remeasuredHeight = 0;
@@ -281,11 +291,11 @@ public class UdfpsDialogMeasureAdapter {
static int calculateBottomSpacerHeightForPortrait(
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
- int navbarBottomInsetPx) {
+ int navbarBottomInsetPx, float scaleFactor) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromBottom = displayHeightPx
- - location.sensorLocationY
- - location.sensorRadius;
+ - (int) (scaleFactor * location.sensorLocationY)
+ - (int) (scaleFactor * location.sensorRadius);
final int spacerHeight = sensorDistanceFromBottom
- textIndicatorHeightPx
@@ -298,7 +308,8 @@ public class UdfpsDialogMeasureAdapter {
+ ", Distance from bottom: " + sensorDistanceFromBottom
+ ", Bottom margin: " + dialogMarginPx
+ ", Navbar bottom inset: " + navbarBottomInsetPx
- + ", Bottom spacer height (portrait): " + spacerHeight);
+ + ", Bottom spacer height (portrait): " + spacerHeight
+ + ", Scale Factor: " + scaleFactor);
}
return spacerHeight;
@@ -346,11 +357,11 @@ public class UdfpsDialogMeasureAdapter {
@VisibleForTesting
static int calculateHorizontalSpacerWidthForLandscape(
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
- int dialogMarginPx, int navbarHorizontalInsetPx) {
+ int dialogMarginPx, int navbarHorizontalInsetPx, float scaleFactor) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromEdge = displayWidthPx
- - location.sensorLocationY
- - location.sensorRadius;
+ - (int) (scaleFactor * location.sensorLocationY)
+ - (int) (scaleFactor * location.sensorRadius);
final int horizontalPadding = sensorDistanceFromEdge
- dialogMarginPx
@@ -361,7 +372,8 @@ public class UdfpsDialogMeasureAdapter {
+ ", Distance from edge: " + sensorDistanceFromEdge
+ ", Dialog margin: " + dialogMarginPx
+ ", Navbar horizontal inset: " + navbarHorizontalInsetPx
- + ", Horizontal spacer width (landscape): " + horizontalPadding);
+ + ", Horizontal spacer width (landscape): " + horizontalPadding
+ + ", Scale Factor: " + scaleFactor);
}
return horizontalPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java
new file mode 100644
index 000000000000..9b7d49883222
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (C) 2022 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.bluetooth;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.media.MediaDataUtils;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+/**
+ * Dialog for showing le audio broadcasting dialog.
+ */
+public class BroadcastDialog extends SystemUIDialog {
+
+ private static final String TAG = "BroadcastDialog";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private Context mContext;
+ private UiEventLogger mUiEventLogger;
+ @VisibleForTesting
+ protected View mDialogView;
+ private MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private String mSwitchBroadcastApp;
+ private String mOutputPackageName;
+
+ public BroadcastDialog(Context context, MediaOutputDialogFactory mediaOutputDialogFactory,
+ String switchBroadcastApp, String outputPkgName, UiEventLogger uiEventLogger) {
+ super(context);
+ if (DEBUG) {
+ Log.d(TAG, "Init BroadcastDialog");
+ }
+
+ mContext = getContext();
+ mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ mSwitchBroadcastApp = switchBroadcastApp;
+ mOutputPackageName = outputPkgName;
+ mUiEventLogger = uiEventLogger;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (DEBUG) {
+ Log.d(TAG, "onCreate");
+ }
+
+ mUiEventLogger.log(BroadcastDialogEvent.BROADCAST_DIALOG_SHOW);
+ mDialogView = LayoutInflater.from(mContext).inflate(R.layout.broadcast_dialog, null);
+ final Window window = getWindow();
+ window.setContentView(mDialogView);
+
+ TextView title = mDialogView.requireViewById(R.id.dialog_title);
+ TextView subTitle = mDialogView.requireViewById(R.id.dialog_subtitle);
+ title.setText(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_title,
+ MediaDataUtils.getAppLabel(mContext, mOutputPackageName,
+ mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_unknown_name))));
+ subTitle.setText(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title,
+ mSwitchBroadcastApp));
+
+ Button switchBroadcast = mDialogView.requireViewById(R.id.switch_broadcast);
+ Button changeOutput = mDialogView.requireViewById(R.id.change_output);
+ Button cancelBtn = mDialogView.requireViewById(R.id.cancel);
+ switchBroadcast.setText(mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_switch_app, mSwitchBroadcastApp), null);
+ changeOutput.setOnClickListener((view) -> {
+ mMediaOutputDialogFactory.create(mOutputPackageName, true, null);
+ dismiss();
+ });
+ cancelBtn.setOnClickListener((view) -> {
+ if (DEBUG) {
+ Log.d(TAG, "BroadcastDialog dismiss.");
+ }
+ dismiss();
+ });
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus && isShowing()) {
+ dismiss();
+ }
+ }
+
+ public enum BroadcastDialogEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The Broadcast dialog became visible on the screen.")
+ BROADCAST_DIALOG_SHOW(1062);
+
+ private final int mId;
+
+ BroadcastDialogEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
new file mode 100644
index 000000000000..8a54345ae28c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2022 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.bluetooth;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+
+import javax.inject.Inject;
+
+/**
+ * Controller to create BroadcastDialog objects.
+ */
+@SysUISingleton
+public class BroadcastDialogController {
+
+ private Context mContext;
+ private UiEventLogger mUiEventLogger;
+ private DialogLaunchAnimator mDialogLaunchAnimator;
+ private MediaOutputDialogFactory mMediaOutputDialogFactory;
+
+ @Inject
+ public BroadcastDialogController(Context context, UiEventLogger uiEventLogger,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ MediaOutputDialogFactory mediaOutputDialogFactory) {
+ mContext = context;
+ mUiEventLogger = uiEventLogger;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
+ mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ }
+
+ public void createBroadcastDialog(String switchAppName, String outputPkgName,
+ boolean aboveStatusBar, View view) {
+ BroadcastDialog broadcastDialog = new BroadcastDialog(mContext, mMediaOutputDialogFactory,
+ switchAppName, outputPkgName, mUiEventLogger);
+ if (view != null) {
+ mDialogLaunchAnimator.showFromView(broadcastDialog, view);
+ } else {
+ broadcastDialog.show();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index e5da38936593..4773f2a3b13e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -18,9 +18,9 @@ package com.android.systemui.classifier;
import android.view.MotionEvent;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -33,13 +33,13 @@ import java.util.ListIterator;
*/
public class TimeLimitedMotionEventBuffer implements List<MotionEvent> {
- private final LinkedList<MotionEvent> mMotionEvents;
+ private final List<MotionEvent> mMotionEvents;
private final long mMaxAgeMs;
public TimeLimitedMotionEventBuffer(long maxAgeMs) {
super();
mMaxAgeMs = maxAgeMs;
- mMotionEvents = new LinkedList<>();
+ mMotionEvents = new ArrayList<>();
}
private void ejectOldEvents() {
@@ -47,7 +47,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> {
return;
}
Iterator<MotionEvent> iter = listIterator();
- long mostRecentMs = mMotionEvents.getLast().getEventTime();
+ long mostRecentMs = mMotionEvents.get(mMotionEvents.size() - 1).getEventTime();
while (iter.hasNext()) {
MotionEvent ev = iter.next();
if (mostRecentMs - ev.getEventTime() > mMaxAgeMs) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index bed553e6e4d6..2ea596788091 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -33,6 +33,7 @@ import android.service.controls.actions.ControlAction
import android.util.ArrayMap
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_USER_ID
import com.android.systemui.Dumpable
import com.android.systemui.backup.BackupHelper
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -43,6 +44,7 @@ import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index 0cf3333d12a6..8ba6f1c4a411 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -18,6 +18,8 @@ package com.android.systemui.dagger;
import android.content.BroadcastReceiver;
+import com.android.systemui.GuestResetOrExitSessionReceiver;
+import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.media.dialog.MediaOutputDialogReceiver;
import com.android.systemui.people.widget.PeopleSpaceWidgetPinnedReceiver;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
@@ -89,4 +91,21 @@ public abstract class DefaultBroadcastReceiverBinder {
public abstract BroadcastReceiver bindPeopleSpaceWidgetProvider(
PeopleSpaceWidgetProvider broadcastReceiver);
+ /**
+ *
+ */
+ @Binds
+ @IntoMap
+ @ClassKey(GuestResumeSessionReceiver.class)
+ public abstract BroadcastReceiver bindGuestResumeSessionReceiver(
+ GuestResumeSessionReceiver broadcastReceiver);
+
+ /**
+ *
+ */
+ @Binds
+ @IntoMap
+ @ClassKey(GuestResetOrExitSessionReceiver.class)
+ public abstract BroadcastReceiver bindGuestResetOrExitSessionReceiver(
+ GuestResetOrExitSessionReceiver broadcastReceiver);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 4e48a5261f6b..d70491740af4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -186,7 +186,8 @@ public abstract class ReferenceSystemUIModule {
KeyguardBypassController bypassController,
GroupMembershipManager groupManager,
VisualStabilityProvider visualStabilityProvider,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ @Main Handler handler) {
return new HeadsUpManagerPhone(
context,
headsUpManagerLogger,
@@ -194,7 +195,8 @@ public abstract class ReferenceSystemUIModule {
bypassController,
groupManager,
visualStabilityProvider,
- configurationController
+ configurationController,
+ handler
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 5d34a6987b66..3a1b12955647 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -39,14 +39,12 @@ import com.android.systemui.unfold.UnfoldLatencyTracker;
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.TaskViewFactory;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
@@ -86,15 +84,9 @@ public interface SysUIComponent {
Builder setPip(Optional<Pip> p);
@BindsInstance
- Builder setLegacySplitScreen(Optional<LegacySplitScreen> s);
-
- @BindsInstance
Builder setSplitScreen(Optional<SplitScreen> s);
@BindsInstance
- Builder setAppPairs(Optional<AppPairs> s);
-
- @BindsInstance
Builder setOneHanded(Optional<OneHanded> o);
@BindsInstance
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index b02074a65e9a..1570a7ebc0c4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -26,7 +26,6 @@ import com.android.systemui.tv.TvWMComponent;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.annotations.ShellMainThread;
@@ -37,7 +36,6 @@ import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
@@ -96,15 +94,9 @@ public interface WMComponent {
Optional<Pip> getPip();
@WMSingleton
- Optional<LegacySplitScreen> getLegacySplitScreen();
-
- @WMSingleton
Optional<SplitScreen> getSplitScreen();
@WMSingleton
- Optional<AppPairs> getAppPairs();
-
- @WMSingleton
Optional<Bubbles> getBubbles();
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 74949d094e33..d7b7777559da 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -183,22 +183,22 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
}
private void updateBurnInOffsets() {
- int burnInOffset = mMaxBurnInOffset;
-
// Make sure the offset starts at zero, to avoid a big jump in the overlay when it first
// appears.
- long millisSinceStart = System.currentTimeMillis() - mJitterStartTimeMillis;
+ final long millisSinceStart = System.currentTimeMillis() - mJitterStartTimeMillis;
+ final int burnInOffset;
if (millisSinceStart < mMillisUntilFullJitter) {
float lerpAmount = (float) millisSinceStart / (float) mMillisUntilFullJitter;
- burnInOffset = Math.round(MathUtils.lerp(0f, burnInOffset, lerpAmount));
+ burnInOffset = Math.round(MathUtils.lerp(0f, mMaxBurnInOffset, lerpAmount));
+ } else {
+ burnInOffset = mMaxBurnInOffset;
}
// These translation values change slowly, and the set translation methods are idempotent,
// so no translation occurs when the values don't change.
- int burnInOffsetX = getBurnInOffset(burnInOffset * 2, true)
- - burnInOffset;
- int burnInOffsetY = getBurnInOffset(burnInOffset * 2, false)
- - burnInOffset;
+ final int halfBurnInOffset = burnInOffset / 2;
+ final int burnInOffsetX = getBurnInOffset(burnInOffset, true) - halfBurnInOffset;
+ final int burnInOffsetY = getBurnInOffset(burnInOffset, false) - halfBurnInOffset;
mView.setTranslationX(burnInOffsetX);
mView.setTranslationY(burnInOffsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
index 6589f26dbde2..3dd43866e465 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
@@ -37,7 +37,7 @@ import javax.inject.Inject;
/***
* {@link DreamOverlayNotificationCountProvider} provides the current notification count to
- * registered callbacks.
+ * registered callbacks. Ongoing notifications are not included in the count.
*/
@SysUISingleton
public class DreamOverlayNotificationCountProvider
@@ -49,6 +49,10 @@ public class DreamOverlayNotificationCountProvider
@Override
public void onNotificationPosted(
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
+ if (sbn.isOngoing()) {
+ // Don't count ongoing notifications.
+ return;
+ }
mNotificationKeys.add(sbn.getKey());
reportNotificationCountChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
index a83e006dfa2f..7666eb84acac 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
@@ -26,7 +26,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.complication.ComplicationLayoutParams;
import com.android.systemui.dreams.complication.ComplicationViewModel;
-import com.android.systemui.dreams.smartspace.DreamsSmartspaceController;
+import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import java.util.List;
@@ -43,7 +43,7 @@ public class SmartSpaceComplication implements Complication {
* SystemUI.
*/
public static class Registrant extends CoreStartable {
- private final DreamsSmartspaceController mSmartSpaceController;
+ private final DreamSmartspaceController mSmartSpaceController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final SmartSpaceComplication mComplication;
@@ -66,7 +66,7 @@ public class SmartSpaceComplication implements Complication {
public Registrant(Context context,
DreamOverlayStateController dreamOverlayStateController,
SmartSpaceComplication smartSpaceComplication,
- DreamsSmartspaceController smartSpaceController) {
+ DreamSmartspaceController smartSpaceController) {
super(context);
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = smartSpaceComplication;
@@ -90,12 +90,12 @@ public class SmartSpaceComplication implements Complication {
private static class SmartSpaceComplicationViewHolder implements ViewHolder {
private static final int SMARTSPACE_COMPLICATION_WEIGHT = 10;
- private final DreamsSmartspaceController mSmartSpaceController;
+ private final DreamSmartspaceController mSmartSpaceController;
private final Context mContext;
protected SmartSpaceComplicationViewHolder(
Context context,
- DreamsSmartspaceController smartSpaceController) {
+ DreamSmartspaceController smartSpaceController) {
mSmartSpaceController = smartSpaceController;
mContext = context;
}
@@ -120,12 +120,12 @@ public class SmartSpaceComplication implements Complication {
}
}
- private final DreamsSmartspaceController mSmartSpaceController;
+ private final DreamSmartspaceController mSmartSpaceController;
private final Context mContext;
@Inject
public SmartSpaceComplication(Context context,
- DreamsSmartspaceController smartSpaceController) {
+ DreamSmartspaceController smartSpaceController) {
mContext = context;
mSmartSpaceController = smartSpaceController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
index f5c5a434a077..3d1bc59b433a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
@@ -18,10 +18,12 @@ package com.android.systemui.dreams.complication;
import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS;
import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT;
import android.app.smartspace.SmartspaceAction;
import android.app.smartspace.SmartspaceTarget;
import android.content.Context;
+import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
@@ -31,6 +33,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.R;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.util.ViewController;
@@ -132,15 +135,21 @@ public class DreamWeatherComplication implements Complication {
*/
static class DreamWeatherViewController extends ViewController<TextView> {
private final LockscreenSmartspaceController mSmartSpaceController;
+ private final ActivityStarter mActivityStarter;
+ private final String mSmartspaceTrampolineActivityComponent;
private SmartspaceTargetListener mSmartspaceTargetListener;
@Inject
DreamWeatherViewController(
@Named(DREAM_WEATHER_COMPLICATION_VIEW) TextView view,
+ @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) String smartspaceTrampoline,
+ ActivityStarter activityStarter,
LockscreenSmartspaceController smartspaceController
) {
super(view);
+ mActivityStarter = activityStarter;
mSmartSpaceController = smartspaceController;
+ mSmartspaceTrampolineActivityComponent = smartspaceTrampoline;
}
@Override
@@ -172,6 +181,15 @@ public class DreamWeatherComplication implements Complication {
R.dimen.smart_action_button_icon_padding));
}
+ mView.setOnClickListener(v -> {
+ final Intent intent = headerAction.getIntent();
+ if (intent != null && intent.getComponent() != null
+ && intent.getComponent().getClassName()
+ .equals(mSmartspaceTrampolineActivityComponent)) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ intent, 0 /*delay*/);
+ }
+ });
}
});
mSmartSpaceController.addListener(mSmartspaceTargetListener);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
index 536f3dcd2850..a1660f2b43f2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
@@ -19,6 +19,7 @@ package com.android.systemui.dreams.complication.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -76,6 +77,7 @@ public interface DreamWeatherComplicationComponent {
String DREAM_WEATHER_COMPLICATION_VIEW = "weather_complication_view";
String DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS =
"weather_complication_layout_params";
+ String SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT = "smartspace_trampoline_activity";
// Order weight of insert into parent container
int INSERT_ORDER_WEIGHT = 1;
@@ -106,5 +108,15 @@ public interface DreamWeatherComplicationComponent {
ComplicationLayoutParams.DIRECTION_END,
INSERT_ORDER_WEIGHT);
}
+
+ /**
+ * Provides the smartspace trampoline activity component.
+ */
+ @Provides
+ @DreamWeatherComplicationScope
+ @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT)
+ static String provideSmartspaceTrampolineActivityComponent(Context context) {
+ return context.getString(R.string.config_smartspaceTrampolineActivityComponent);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index c1dff248818f..cd23f149cf7d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -17,10 +17,14 @@
package com.android.systemui.dreams.dagger;
import android.content.Context;
+import android.content.res.Resources;
import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
+import javax.inject.Named;
+
import dagger.Module;
import dagger.Provides;
@@ -34,6 +38,10 @@ import dagger.Provides;
DreamOverlayComponent.class,
})
public interface DreamModule {
+ String DREAM_ONLY_ENABLED_FOR_SYSTEM_USER = "dream_only_enabled_for_system_user";
+
+ String DREAM_SUPPORTED = "dream_supported";
+
/**
* Provides an instance of the dream backend.
*/
@@ -41,4 +49,19 @@ public interface DreamModule {
static DreamBackend providesDreamBackend(Context context) {
return DreamBackend.getInstance(context);
}
+
+ /** */
+ @Provides
+ @Named(DREAM_ONLY_ENABLED_FOR_SYSTEM_USER)
+ static boolean providesDreamOnlyEnabledForSystemUser(@Main Resources resources) {
+ return resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser);
+ }
+
+ /** */
+ @Provides
+ @Named(DREAM_SUPPORTED)
+ static boolean providesDreamSupported(@Main Resources resources) {
+ return resources.getBoolean(com.android.internal.R.bool.config_dreamsSupported);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
index a3095472783b..da2cf84318de 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
@@ -46,7 +46,7 @@ import javax.inject.Named
* Controller for managing the smartspace view on the dream
*/
@SysUISingleton
-class DreamsSmartspaceController @Inject constructor(
+class DreamSmartspaceController @Inject constructor(
private val context: Context,
private val smartspaceManager: SmartspaceManager,
private val execution: Execution,
@@ -58,7 +58,7 @@ class DreamsSmartspaceController @Inject constructor(
@Named(DREAM_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>
) {
companion object {
- private const val TAG = "DreamsSmartspaceCtrlr"
+ private const val TAG = "DreamSmartspaceCtrlr"
}
private var session: SmartspaceSession? = null
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index fbca7b1d86d3..f769a2355409 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -44,6 +44,7 @@ import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.util.Optional;
+
import javax.inject.Inject;
import javax.inject.Named;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
index 4965c9dfd00b..3087cdfd0cc0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
@@ -25,6 +25,7 @@ import android.view.View;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.touch.TouchInsetManager;
import com.google.common.util.concurrent.ListenableFuture;
@@ -50,6 +51,7 @@ public class HideComplicationTouchHandler implements DreamTouchHandler {
private final Complication.VisibilityController mVisibilityController;
private final int mRestoreTimeout;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final Handler mHandler;
private final Executor mExecutor;
private final TouchInsetManager mTouchInsetManager;
@@ -65,10 +67,12 @@ public class HideComplicationTouchHandler implements DreamTouchHandler {
HideComplicationTouchHandler(Complication.VisibilityController visibilityController,
@Named(COMPLICATIONS_RESTORE_TIMEOUT) int restoreTimeout,
TouchInsetManager touchInsetManager,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@Main Executor executor,
@Main Handler handler) {
mVisibilityController = visibilityController;
mRestoreTimeout = restoreTimeout;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mHandler = handler;
mTouchInsetManager = touchInsetManager;
mExecutor = executor;
@@ -80,10 +84,13 @@ public class HideComplicationTouchHandler implements DreamTouchHandler {
Log.d(TAG, "onSessionStart");
}
+ final boolean bouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
+
// If other sessions are interested in this touch, do not fade out elements.
- if (session.getActiveSessionCount() > 1) {
+ if (session.getActiveSessionCount() > 1 || bouncerShowing) {
if (DEBUG) {
- Log.d(TAG, "multiple active touch sessions, not fading");
+ Log.d(TAG, "not fading. Active session count: " + session.getActiveSessionCount()
+ + ". Bouncer showing: " + bouncerShowing);
}
session.pop();
return;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index afa7d5e0a9c4..55bbcb654cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -158,12 +158,21 @@ public class Flags {
// 1000 - dock
public static final BooleanFlag SIMULATE_DOCK_THROUGH_CHARGING =
new BooleanFlag(1000, true);
+ public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, false);
+
// 1100 - windowing
@Keep
public static final SysPropBooleanFlag WM_ENABLE_SHELL_TRANSITIONS =
new SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false);
+ /**
+ * b/170163464: animate bubbles expanded view collapse with home gesture
+ */
+ @Keep
+ public static final SysPropBooleanFlag BUBBLES_HOME_GESTURE =
+ new SysPropBooleanFlag(1101, "persist.wm.debug.bubbles_home_gesture", false);
+
// 1200 - predictive back
@Keep
public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index 5aedbdc20b31..bd00ce61a7e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -34,8 +34,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -71,7 +71,7 @@ public class KeyguardIndicationRotateTextViewController extends
@Nullable private ShowNextIndication mShowNextIndicationRunnable;
// List of indication types to show. The next indication to show is always at index 0
- private final List<Integer> mIndicationQueue = new LinkedList<>();
+ private final List<Integer> mIndicationQueue = new ArrayList<>();
private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE;
private CharSequence mCurrMessage;
private long mLastIndicationSwitch;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e379d766f0ca..067cbd8e1e21 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,6 +40,7 @@ import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.WindowConfiguration;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -921,6 +922,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
}
final RemoteAnimationTarget primary = apps[0];
+ final boolean isDream = (apps[0].taskInfo.topActivityType
+ == WindowConfiguration.ACTIVITY_TYPE_DREAM);
final SyncRtSurfaceTransactionApplier applier =
new SyncRtSurfaceTransactionApplier(
@@ -942,20 +945,24 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
final float surfaceHeight = primary.screenSpaceBounds.height();
- mUnoccludeMatrix.setTranslate(
- 0f,
- (1f - animatedValue)
- * surfaceHeight
- * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
-
- SyncRtSurfaceTransactionApplier.SurfaceParams params =
+ // Fade for all types of activities.
+ SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
+ paramsBuilder =
new SyncRtSurfaceTransactionApplier.SurfaceParams
.Builder(primary.leash)
- .withMatrix(mUnoccludeMatrix)
- .withCornerRadius(mWindowCornerRadius)
- .withAlpha(animatedValue)
- .build();
- applier.scheduleApply(params);
+ .withAlpha(animatedValue);
+ // Set translate if the occluding activity isn't Dream.
+ if (!isDream) {
+ mUnoccludeMatrix.setTranslate(
+ 0f,
+ (1f - animatedValue)
+ * surfaceHeight
+ * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
+
+ paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
+ mWindowCornerRadius);
+ }
+ applier.scheduleApply(paramsBuilder.build());
});
mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1755,12 +1762,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
* Enable the keyguard if the settings are appropriate.
*/
private void doKeyguardLocked(Bundle options) {
- if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
- // Don't show keyguard during half-booted cryptkeeper stage.
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
- return;
- }
-
// if another app is disabling us, don't show
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 972e93b886b8..d8bde551b7f3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -70,6 +70,7 @@ import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -188,6 +189,11 @@ public class MediaControlPanel {
private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener =
this::setIsSeekBarEnabled;
+ private final BroadcastDialogController mBroadcastDialogController;
+ private boolean mIsCurrentBroadcastedApp = false;
+ private boolean mShowBroadcastDialogButton = false;
+ private String mSwitchBroadcastApp;
+
/**
* Initialize a new control panel
*
@@ -213,7 +219,8 @@ public class MediaControlPanel {
MediaUiEventLogger logger,
KeyguardStateController keyguardStateController,
ActivityIntentHelper activityIntentHelper,
- NotificationLockscreenUserManager lockscreenUserManager) {
+ NotificationLockscreenUserManager lockscreenUserManager,
+ BroadcastDialogController broadcastDialogController) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mMainExecutor = mainExecutor;
@@ -230,6 +237,7 @@ public class MediaControlPanel {
mKeyguardStateController = keyguardStateController;
mActivityIntentHelper = activityIntentHelper;
mLockscreenUserManager = lockscreenUserManager;
+ mBroadcastDialogController = broadcastDialogController;
mSeekBarViewModel.setLogSeek(() -> {
if (mPackageName != null && mInstanceId != null) {
@@ -449,7 +457,10 @@ public class MediaControlPanel {
final MediaController controller = getController();
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
- bindOutputSwitcherChip(data);
+ // Show the broadcast dialog button only when the le audio is enabled.
+ mShowBroadcastDialogButton =
+ data.getDevice() != null && data.getDevice().getShowBroadcastButton();
+ bindOutputSwitcherAndBroadcastButton(mShowBroadcastDialogButton, data);
bindGutsMenuForPlayer(data);
bindPlayerContentDescription(data);
bindScrubbingTime(data);
@@ -467,21 +478,40 @@ public class MediaControlPanel {
Trace.endSection();
}
- private void bindOutputSwitcherChip(MediaData data) {
- // Output switcher chip
+ private void bindOutputSwitcherAndBroadcastButton(boolean showBroadcastButton, MediaData data) {
ViewGroup seamlessView = mMediaViewHolder.getSeamless();
seamlessView.setVisibility(View.VISIBLE);
ImageView iconView = mMediaViewHolder.getSeamlessIcon();
TextView deviceName = mMediaViewHolder.getSeamlessText();
final MediaDeviceData device = data.getDevice();
- // 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;
- mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha);
- seamlessView.setEnabled(!seamlessDisabled);
- CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device);
+ final boolean enabled;
+ final boolean seamlessDisabled;
+ final int iconResource;
+ CharSequence deviceString;
+ if (showBroadcastButton) {
+ // TODO(b/233698402): Use the package name instead of app label to avoid the
+ // unexpected result.
+ mIsCurrentBroadcastedApp = device != null
+ && TextUtils.equals(device.getName(),
+ MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_unknown_name)));
+ seamlessDisabled = !mIsCurrentBroadcastedApp;
+ // Always be enabled if the broadcast button is shown
+ enabled = true;
+ deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name);
+ iconResource = R.drawable.settings_input_antenna;
+ } else {
+ // Disable clicking on output switcher for invalid devices and resumption controls
+ seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption();
+ enabled = !seamlessDisabled;
+ deviceString = mContext.getString(R.string.media_seamless_other_device);
+ iconResource = R.drawable.ic_media_home_devices;
+ }
+
+ mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f);
+ seamlessView.setEnabled(enabled);
+
if (device != null) {
Drawable icon = device.getIcon();
if (icon instanceof AdaptiveIcon) {
@@ -494,7 +524,7 @@ public class MediaControlPanel {
deviceString = device.getName();
} else {
// Set to default icon
- iconView.setImageResource(R.drawable.ic_media_home_devices);
+ iconView.setImageResource(iconResource);
}
deviceName.setText(deviceString);
seamlessView.setContentDescription(deviceString);
@@ -503,21 +533,39 @@ public class MediaControlPanel {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
- mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
- if (device.getIntent() != null) {
- if (device.getIntent().isActivity()) {
- mActivityStarter.startActivity(
- device.getIntent().getIntent(), true);
+
+ if (showBroadcastButton) {
+ // If the current media app is not broadcasted and users press the outputer
+ // button, we should pop up the broadcast dialog to check do they want to
+ // switch broadcast to the other media app, otherwise we still pop up the
+ // media output dialog.
+ if (!mIsCurrentBroadcastedApp) {
+ mLogger.logOpenBroadcastDialog(mUid, mPackageName, mInstanceId);
+ mSwitchBroadcastApp = device.getName().toString();
+ mBroadcastDialogController.createBroadcastDialog(mSwitchBroadcastApp,
+ mPackageName, true, mMediaViewHolder.getSeamlessButton());
} else {
- try {
- device.getIntent().send();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Device pending intent was canceled");
- }
+ mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
+ mMediaOutputDialogFactory.create(mPackageName, true,
+ mMediaViewHolder.getSeamlessButton());
}
} else {
- mMediaOutputDialogFactory.create(mPackageName, true,
- mMediaViewHolder.getSeamlessButton());
+ mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
+ if (device.getIntent() != null) {
+ if (device.getIntent().isActivity()) {
+ mActivityStarter.startActivity(
+ device.getIntent().getIntent(), true);
+ } else {
+ try {
+ device.getIntent().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Device pending intent was canceled");
+ }
+ }
+ } else {
+ mMediaOutputDialogFactory.create(mPackageName, true,
+ mMediaViewHolder.getSeamlessButton());
+ }
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 360f86548e13..b2ab12a81bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -215,5 +215,8 @@ data class MediaDeviceData
val intent: PendingIntent? = null,
/** Unique id for this device */
- val id: String? = null
+ val id: String? = null,
+
+ /** Whether or not to show the broadcast button */
+ val showBroadcastButton: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 6a69d427929e..30ba476abce2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -686,7 +686,8 @@ class MediaDataManager(
val enabled = deviceIntent != null && deviceIntent.isActivity
val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon)
.loadDrawable(sbn.getPackageContext(context))
- device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent)
+ device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent,
+ showBroadcastButton = false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java
new file mode 100644
index 000000000000..b8185b9de7e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2022 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.media;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+
+public class MediaDataUtils {
+
+ public static String getAppLabel(Context context, String packageName, String unknownName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ final PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ applicationInfo = null;
+ }
+ final String applicationName =
+ (String) (applicationInfo != null
+ ? packageManager.getApplicationLabel(applicationInfo)
+ : unknownName);
+ return applicationName;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 8558859638d5..b552d9fb584a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,15 +16,23 @@
package com.android.systemui.media
+import android.bluetooth.BluetoothLeBroadcast
+import android.bluetooth.BluetoothLeBroadcastMetadata
+import android.content.Context
import android.graphics.drawable.Drawable
import android.media.MediaRouter2Manager
import android.media.session.MediaController
+import android.text.TextUtils
+import android.util.Log
import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
import com.android.systemui.Dumpable
+import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
@@ -36,16 +44,20 @@ import java.util.concurrent.Executor
import javax.inject.Inject
private const val PLAYBACK_TYPE_UNKNOWN = 0
+private const val TAG = "MediaDeviceManager"
+private const val DEBUG = true
/**
* Provides information about the route (ie. device) where playback is occurring.
*/
class MediaDeviceManager @Inject constructor(
+ private val context: Context,
private val controllerFactory: MediaControllerFactory,
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
private val muteAwaitConnectionManagerFactory: MediaMuteAwaitConnectionManagerFactory,
private val configurationController: ConfigurationController,
+ private val localBluetoothManager: LocalBluetoothManager?,
@Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
dumpManager: DumpManager
@@ -147,7 +159,8 @@ class MediaDeviceManager @Inject constructor(
val controller: MediaController?,
val localMediaManager: LocalMediaManager,
val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager?
- ) : LocalMediaManager.DeviceCallback, MediaController.Callback() {
+ ) : LocalMediaManager.DeviceCallback, MediaController.Callback(),
+ BluetoothLeBroadcast.Callback {
val token
get() = controller?.sessionToken
@@ -166,7 +179,7 @@ class MediaDeviceManager @Inject constructor(
// A device that is not yet connected but is expected to connect imminently. Because it's
// expected to connect imminently, it should be displayed as the current device.
private var aboutToConnectDeviceOverride: AboutToConnectDevice? = null
-
+ private var broadcastDescription: String? = null
private val configListener = object : ConfigurationController.ConfigurationListener {
override fun onLocaleListChanged() {
updateCurrent()
@@ -238,7 +251,11 @@ class MediaDeviceManager @Inject constructor(
) {
aboutToConnectDeviceOverride = AboutToConnectDevice(
fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress),
- backupMediaDeviceData = MediaDeviceData(enabled = true, deviceIcon, deviceName)
+ backupMediaDeviceData = MediaDeviceData(
+ /* enabled */ enabled = true,
+ /* icon */ deviceIcon,
+ /* name */ deviceName,
+ /* showBroadcastButton */ showBroadcastButton = false)
)
updateCurrent()
}
@@ -248,23 +265,127 @@ class MediaDeviceManager @Inject constructor(
updateCurrent()
}
+
+ override fun onBroadcastStarted(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStarted(), reason = $reason , broadcastId = $broadcastId")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStartFailed(reason: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStartFailed(), reason = $reason")
+ }
+ }
+
+ override fun onBroadcastMetadataChanged(broadcastId: Int,
+ metadata: BluetoothLeBroadcastMetadata) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " +
+ "metadata = $metadata")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStopped(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopped(), reason = $reason , broadcastId = $broadcastId")
+
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStopFailed(reason: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopFailed(), reason = $reason")
+ }
+ }
+
+ override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastUpdated(), reason = $reason , broadcastId = $broadcastId")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastUpdateFailed(), reason = $reason , " +
+ "broadcastId = $broadcastId")
+ }
+ }
+
+ override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
+
+ override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
+
@WorkerThread
private fun updateCurrent() {
- val aboutToConnect = aboutToConnectDeviceOverride
- if (aboutToConnect != null &&
- aboutToConnect.fullMediaDevice == null &&
- aboutToConnect.backupMediaDeviceData != null) {
+ if (isLeAudioBroadcastEnabled()) {
+ current = MediaDeviceData(
+ /* enabled */ true,
+ /* icon */ context.getDrawable(R.drawable.settings_input_antenna),
+ /* name */ broadcastDescription,
+ /* intent */ null,
+ /* showBroadcastButton */ showBroadcastButton = true)
+ } else {
+ val aboutToConnect = aboutToConnectDeviceOverride
+ if (aboutToConnect != null &&
+ aboutToConnect.fullMediaDevice == null &&
+ aboutToConnect.backupMediaDeviceData != null) {
// Only use [backupMediaDeviceData] when we don't have [fullMediaDevice].
current = aboutToConnect.backupMediaDeviceData
return
+ }
+ val device = aboutToConnect?.fullMediaDevice
+ ?: localMediaManager.currentConnectedDevice
+ val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+
+ // If we have a controller but get a null route, then don't trust the device
+ val enabled = device != null && (controller == null || route != null)
+ val name = route?.name?.toString() ?: device?.name
+ current = MediaDeviceData(enabled, device?.iconWithoutBackground, name,
+ id = device?.id, showBroadcastButton = false)
}
- val device = aboutToConnect?.fullMediaDevice ?: localMediaManager.currentConnectedDevice
- val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+ }
- // If we have a controller but get a null route, then don't trust the device
- val enabled = device != null && (controller == null || route != null)
- val name = route?.name?.toString() ?: device?.name
- current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id)
+ private fun isLeAudioBroadcastEnabled(): Boolean {
+ if (localBluetoothManager != null) {
+ val profileManager = localBluetoothManager.profileManager
+ if (profileManager != null) {
+ val bluetoothLeBroadcast = profileManager.leAudioBroadcastProfile
+ if (bluetoothLeBroadcast != null && bluetoothLeBroadcast.isEnabled(null)) {
+ getBroadcastingInfo(bluetoothLeBroadcast)
+ return true
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothLeBroadcast")
+ }
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothProfileManager")
+ }
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothManager")
+ }
+ return false
+ }
+
+ private fun getBroadcastingInfo(bluetoothLeBroadcast: LocalBluetoothLeBroadcast) {
+ var currentBroadcastedApp = bluetoothLeBroadcast.appSourceName
+ // TODO(b/233698402): Use the package name instead of app label to avoid the
+ // unexpected result.
+ // Check the current media app's name is the same with current broadcast app's name
+ // or not.
+ var mediaApp = MediaDataUtils.getAppLabel(
+ context, localMediaManager.packageName,
+ context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name))
+ var isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp)
+ if (isCurrentBroadcastedApp) {
+ broadcastDescription = context.getString(
+ R.string.broadcasting_description_is_broadcasting)
+ } else {
+ broadcastDescription = currentBroadcastedApp
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 8bfb8aae5c91..de2b5c9a4739 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -199,6 +199,14 @@ class MediaHost constructor(
}
}
+ override var squishFraction: Float = 1.0f
+ set(value) {
+ if (!value.equals(field)) {
+ field = value
+ changedListener?.invoke()
+ }
+ }
+
override var showsOnlyActiveMedia: Boolean = false
set(value) {
if (!value.equals(field)) {
@@ -249,6 +257,7 @@ class MediaHost constructor(
override fun copy(): MediaHostState {
val mediaHostState = MediaHostStateHolder()
mediaHostState.expansion = expansion
+ mediaHostState.squishFraction = squishFraction
mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
mediaHostState.measurementInput = measurementInput?.copy()
mediaHostState.visible = visible
@@ -267,6 +276,9 @@ class MediaHost constructor(
if (expansion != other.expansion) {
return false
}
+ if (squishFraction != other.squishFraction) {
+ return false
+ }
if (showsOnlyActiveMedia != other.showsOnlyActiveMedia) {
return false
}
@@ -285,6 +297,7 @@ class MediaHost constructor(
override fun hashCode(): Int {
var result = measurementInput?.hashCode() ?: 0
result = 31 * result + expansion.hashCode()
+ result = 31 * result + squishFraction.hashCode()
result = 31 * result + falsingProtectionNeeded.hashCode()
result = 31 * result + showsOnlyActiveMedia.hashCode()
result = 31 * result + if (visible) 1 else 2
@@ -325,6 +338,11 @@ interface MediaHostState {
var expansion: Float
/**
+ * Fraction of the height animation.
+ */
+ var squishFraction: Float
+
+ /**
* Is this host only showing active media or is it showing all of them including resumption?
*/
var showsOnlyActiveMedia: Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index cc06b6c67879..b52565d57f27 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -33,6 +33,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
import com.android.systemui.util.time.SystemClock
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
index 52f5cc568ba4..0baf01e7476f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
@@ -176,6 +176,11 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName,
instanceId)
}
+
+ fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, uid, packageName,
+ instanceId)
+ }
}
enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@@ -273,7 +278,10 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
MEDIA_RECOMMENDATION_ITEM_TAP(1044),
@UiEvent(doc = "User tapped on a media recommendation card")
- MEDIA_RECOMMENDATION_CARD_TAP(1045);
+ MEDIA_RECOMMENDATION_CARD_TAP(1045),
+
+ @UiEvent(doc = "User opened the broadcast dialog from a media control")
+ MEDIA_OPEN_BROADCAST_DIALOG(1079);
override fun getId() = metricId
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index deb5cbafccc4..ae62355e6768 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -18,6 +18,7 @@ package com.android.systemui.media
import android.content.Context
import android.content.res.Configuration
+import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -276,53 +277,79 @@ class MediaViewController @Inject constructor(
}
/**
+ * Apply squishFraction to a copy of viewState such that the cached version is untouched.
+ */
+ @VisibleForTesting
+ internal fun squishViewState(
+ viewState: TransitionViewState,
+ squishFraction: Float
+ ): TransitionViewState {
+ val squishedViewState = viewState.copy()
+ squishedViewState.height = (squishedViewState.height * squishFraction).toInt()
+ val albumArtViewState = squishedViewState.widgetStates.get(R.id.album_art)
+ if (albumArtViewState != null) {
+ albumArtViewState.height = squishedViewState.height
+ }
+ return squishedViewState
+ }
+
+ /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
- private fun obtainViewState(state: MediaHostState?): TransitionViewState? {
+ @VisibleForTesting
+ public fun obtainViewState(state: MediaHostState?): TransitionViewState? {
if (state == null || state.measurementInput == null) {
return null
}
// Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
var cacheKey = getKey(state, isGutsVisible, tmpKey)
val viewState = viewStates[cacheKey]
+
if (viewState != null) {
// we already have cached this measurement, let's continue
+ if (state.squishFraction < 1f) {
+ return squishViewState(viewState, state.squishFraction)
+ }
return viewState
}
// Copy the key since this might call recursively into it and we're using tmpKey
cacheKey = cacheKey.copy()
val result: TransitionViewState?
+ if (transitionLayout == null) {
+ return null
+ }
- if (transitionLayout != null) {
- // Let's create a new measurement
- if (state.expansion == 0.0f || state.expansion == 1.0f) {
- result = transitionLayout!!.calculateViewState(
- state.measurementInput!!,
- constraintSetForExpansion(state.expansion),
- TransitionViewState())
-
- setGutsViewState(result)
- // We don't want to cache interpolated or null states as this could quickly fill up
- // our cache. We only cache the start and the end states since the interpolation
- // is cheap
- viewStates[cacheKey] = result
- } else {
- // This is an interpolated state
- val startState = state.copy().also { it.expansion = 0.0f }
-
- // Given that we have a measurement and a view, let's get (guaranteed) viewstates
- // from the start and end state and interpolate them
- val startViewState = obtainViewState(startState) as TransitionViewState
- val endState = state.copy().also { it.expansion = 1.0f }
- val endViewState = obtainViewState(endState) as TransitionViewState
- result = layoutController.getInterpolatedState(
- startViewState,
- endViewState,
- state.expansion)
- }
+ // Not cached. Let's create a new measurement
+ if (state.expansion == 0.0f || state.expansion == 1.0f) {
+ result = transitionLayout!!.calculateViewState(
+ state.measurementInput!!,
+ constraintSetForExpansion(state.expansion),
+ TransitionViewState())
+ // We don't want to cache interpolated or null states as this could quickly fill up
+ // our cache. We only cache the start and the end states since the interpolation
+ // is cheap
+ setGutsViewState(result)
+ viewStates[cacheKey] = result
+ logger.logMediaSize("measured new viewState", result.width, result.height)
} else {
- result = null
+ // This is an interpolated state
+ val startState = state.copy().also { it.expansion = 0.0f }
+
+ // Given that we have a measurement and a view, let's get (guaranteed) viewstates
+ // from the start and end state and interpolate them
+ val startViewState = obtainViewState(startState) as TransitionViewState
+ val endState = state.copy().also { it.expansion = 1.0f }
+
+ val endViewState = obtainViewState(endState) as TransitionViewState
+ result = layoutController.getInterpolatedState(
+ startViewState,
+ endViewState,
+ state.expansion)
+ logger.logMediaSize("interpolated viewState", result.width, result.height)
+ }
+ if (state.squishFraction < 1f) {
+ return squishViewState(result, state.squishFraction)
}
return result
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index b407e76f1b11..9f5ad8ba1fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -260,7 +260,7 @@ public abstract class MediaOutputBaseAdapter extends
if (bFocused) {
mTwoLineTitleText.setTypeface(Typeface.create(mContext.getString(
- com.android.internal.R.string.config_headlineFontFamilyMedium),
+ com.android.internal.R.string.config_headlineFontFamilyMedium),
Typeface.NORMAL));
} else {
mTwoLineTitleText.setTypeface(Typeface.create(mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index e5913061ef3f..fa6db01275b0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -314,19 +314,19 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mHeaderIcon.setImageResource(iconRes);
} else if (iconCompat != null) {
Icon icon = iconCompat.toIcon(mContext);
- if (icon.getType() != Icon.TYPE_BITMAP && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {
- // icon doesn't support getBitmap, use default value for color scheme
- updateButtonBackgroundColorFilter();
- } else {
- Configuration config = mContext.getResources().getConfiguration();
- int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
- boolean isDarkThemeOn = currentNightMode == Configuration.UI_MODE_NIGHT_YES;
- WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(icon.getBitmap());
- colorSetUpdated = !wallpaperColors.equals(mWallpaperColors);
- if (colorSetUpdated) {
- mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
- updateButtonBackgroundColorFilter();
- }
+ Configuration config = mContext.getResources().getConfiguration();
+ int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ boolean isDarkThemeOn = currentNightMode == Configuration.UI_MODE_NIGHT_YES;
+ WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(icon.getBitmap());
+ colorSetUpdated = !wallpaperColors.equals(mWallpaperColors);
+ if (colorSetUpdated) {
+ mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
+ ColorFilter buttonColorFilter = new PorterDuffColorFilter(
+ mAdapter.getController().getColorButtonBackground(),
+ PorterDuff.Mode.SRC_IN);
+ mDoneButton.getBackground().setColorFilter(buttonColorFilter);
+ mStopButton.getBackground().setColorFilter(buttonColorFilter);
+ mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
@@ -368,15 +368,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mStopButton.setOnClickListener(v -> onStopButtonClick());
}
- private void updateButtonBackgroundColorFilter() {
- ColorFilter buttonColorFilter = new PorterDuffColorFilter(
- mAdapter.getController().getColorButtonBackground(),
- PorterDuff.Mode.SRC_IN);
- mDoneButton.getBackground().setColorFilter(buttonColorFilter);
- mStopButton.getBackground().setColorFilter(buttonColorFilter);
- mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
- }
-
private Drawable resizeDrawable(Drawable drawable, int size) {
if (drawable == null) {
return null;
@@ -482,7 +473,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
abstract int getStopButtonVisibility();
public CharSequence getStopButtonText() {
- return mContext.getText(R.string.keyboard_key_media_stop);
+ return mContext.getText(R.string.media_output_dialog_button_stop_casting);
}
public void onStopButtonClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 9248433a4a90..026a3055b01b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -104,7 +104,7 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
@Override
public CharSequence getStopButtonText() {
- int resId = R.string.keyboard_key_media_stop;
+ int resId = R.string.media_output_dialog_button_stop_casting;
if (isBroadcastSupported() && mMediaOutputController.isPlaying()
&& !mMediaOutputController.isBluetoothLeBroadcastEnabled()) {
resId = R.string.media_output_broadcast;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index aa38b781229c..47b1bff29a10 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -215,8 +215,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
private final UiEventLogger mUiEventLogger;
private final NavBarHelper mNavBarHelper;
private final NotificationShadeDepthController mNotificationShadeDepthController;
- private final UserContextProvider mUserContextProvider;
private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
+ private final UserContextProvider mUserContextProvider;
private final RegionSamplingHelper mRegionSamplingHelper;
private final int mNavColorSampleMargin;
private NavigationBarFrame mFrame;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 3fc9afe6ea94..ad3cfa359a52 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -812,6 +812,7 @@ public class NavigationBarView extends FrameLayout {
mImeDrawsImeNavBar = imeDrawsImeNavBar;
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
+ mRotationButtonController.onNavigationModeChanged(mNavBarMode);
updateRotationButton();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
new file mode 100644
index 000000000000..56ad19ae89ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
@@ -0,0 +1,340 @@
+package com.android.systemui.navigationbar.gestural
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.RectF
+import android.view.View
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.internal.util.LatencyTracker
+import com.android.settingslib.Utils
+import com.android.systemui.navigationbar.gestural.BackPanelController.DelayedOnAnimationEndListener
+
+private const val TAG = "BackPanel"
+private const val DEBUG = false
+
+class BackPanel(context: Context, private val latencyTracker: LatencyTracker) : View(context) {
+
+ var arrowsPointLeft = false
+ set(value) {
+ if (field != value) {
+ invalidate()
+ field = value
+ }
+ }
+
+ // Arrow color and shape
+ private val arrowPath = Path()
+ private val arrowPaint = Paint()
+
+ // Arrow background color and shape
+ private var arrowBackgroundRect = RectF()
+ private var arrowBackgroundPaint = Paint()
+
+ // True if the panel is currently on the left of the screen
+ var isLeftPanel = false
+
+ /**
+ * Used to track back arrow latency from [android.view.MotionEvent.ACTION_DOWN] to [onDraw]
+ */
+ private var trackingBackArrowLatency = false
+
+ /**
+ * The length of the arrow measured horizontally. Used for animating [arrowPath]
+ */
+ private var arrowLength = AnimatedFloat("arrowLength", SpringForce())
+
+ /**
+ * The height of the arrow measured vertically from its center to its top (i.e. half the total
+ * height). Used for animating [arrowPath]
+ */
+ private var arrowHeight = AnimatedFloat("arrowHeight", SpringForce())
+
+ private val backgroundWidth = AnimatedFloat(
+ name = "backgroundWidth",
+ SpringForce().apply {
+ stiffness = 600f
+ dampingRatio = 0.65f
+ })
+
+ private val backgroundHeight = AnimatedFloat(
+ name = "backgroundHeight",
+ SpringForce().apply {
+ stiffness = 600f
+ dampingRatio = 0.65f
+ })
+
+ /**
+ * Corners of the background closer to the edge of the screen (where the arrow appeared from).
+ * Used for animating [arrowBackgroundRect]
+ */
+ private val backgroundEdgeCornerRadius = AnimatedFloat(
+ name = "backgroundEdgeCornerRadius",
+ SpringForce().apply {
+ stiffness = 400f
+ dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
+ })
+
+ /**
+ * Corners of the background further from the edge of the screens (toward the direction the
+ * arrow is being dragged). Used for animating [arrowBackgroundRect]
+ */
+ private val backgroundDragCornerRadius = AnimatedFloat(
+ name = "backgroundDragCornerRadius",
+ SpringForce().apply {
+ stiffness = 2200f
+ dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
+ })
+
+ /**
+ * Left/right position of the background relative to the canvas. Also corresponds with the
+ * background's margin relative to the screen edge. The arrow will be centered within the
+ * background.
+ */
+ private var horizontalTranslation = AnimatedFloat("horizontalTranslation", SpringForce())
+
+ /**
+ * Canvas vertical translation. How far up/down the arrow and background appear relative to the
+ * canvas.
+ */
+ private var verticalTranslation: AnimatedFloat =
+ AnimatedFloat("verticalTranslation", SpringForce().apply {
+ stiffness = SpringForce.STIFFNESS_MEDIUM
+ })
+
+ /**
+ * Use for drawing debug info. Can only be set if [DEBUG]=true
+ */
+ var drawDebugInfo: ((canvas: Canvas) -> Unit)? = null
+ set(value) {
+ if (DEBUG) field = value
+ }
+
+ internal fun updateArrowPaint(arrowThickness: Float) {
+ // Arrow constants
+ arrowPaint.strokeWidth = arrowThickness
+
+ arrowPaint.color =
+ Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
+ arrowBackgroundPaint.color = Utils.getColorAccentDefaultColor(context)
+ }
+
+ private inner class AnimatedFloat(name: String, springForce: SpringForce) {
+ // The resting position when not stretched by a touch drag
+ private var restingPosition = 0f
+
+ // The current position as updated by the SpringAnimation
+ var pos = 0f
+ set(v) {
+ if (field != v) {
+ field = v
+ invalidate()
+ }
+ }
+
+ val animation: SpringAnimation
+
+ init {
+ val floatProp = object : FloatPropertyCompat<AnimatedFloat>(name) {
+ override fun setValue(animatedFloat: AnimatedFloat, value: Float) {
+ animatedFloat.pos = value
+ }
+
+ override fun getValue(animatedFloat: AnimatedFloat): Float = animatedFloat.pos
+ }
+ animation = SpringAnimation(this, floatProp)
+ animation.spring = springForce
+ }
+
+ fun snapTo(newPosition: Float) {
+ animation.cancel()
+ restingPosition = newPosition
+ animation.spring.finalPosition = newPosition
+ pos = newPosition
+ }
+
+ fun stretchTo(stretchAmount: Float) {
+ animation.animateToFinalPosition(restingPosition + stretchAmount)
+ }
+
+ fun updateRestingPosition(pos: Float, animated: Boolean) {
+ restingPosition = pos
+ if (animated)
+ animation.animateToFinalPosition(restingPosition)
+ else
+ snapTo(restingPosition)
+ }
+ }
+
+ init {
+ visibility = GONE
+ arrowPaint.apply {
+ style = Paint.Style.STROKE
+ strokeCap = Paint.Cap.SQUARE
+ }
+ arrowBackgroundPaint.apply {
+ style = Paint.Style.FILL
+ strokeJoin = Paint.Join.ROUND
+ strokeCap = Paint.Cap.ROUND
+ }
+ }
+
+ private fun calculateArrowPath(dx: Float, dy: Float): Path {
+ arrowPath.reset()
+ arrowPath.moveTo(dx, -dy)
+ arrowPath.lineTo(0f, 0f)
+ arrowPath.lineTo(dx, dy)
+ arrowPath.moveTo(dx, -dy)
+ return arrowPath
+ }
+
+ fun addEndListener(endListener: DelayedOnAnimationEndListener): Boolean {
+ return if (horizontalTranslation.animation.isRunning) {
+ horizontalTranslation.animation.addEndListener(endListener)
+ true
+ } else {
+ endListener.runNow()
+ false
+ }
+ }
+
+ fun setStretch(
+ arrowLengthStretch: Float,
+ arrowHeightStretch: Float,
+ backgroundWidthStretch: Float,
+ backgroundHeightStretch: Float,
+ backgroundEdgeCornerRadiusStretch: Float,
+ backgroundDragCornerRadiusStretch: Float,
+ horizontalTranslationStretch: Float
+ ) {
+ arrowLength.stretchTo(arrowLengthStretch)
+ arrowHeight.stretchTo(arrowHeightStretch)
+ backgroundWidth.stretchTo(backgroundWidthStretch)
+ backgroundHeight.stretchTo(backgroundHeightStretch)
+ backgroundEdgeCornerRadius.stretchTo(backgroundEdgeCornerRadiusStretch)
+ backgroundDragCornerRadius.stretchTo(backgroundDragCornerRadiusStretch)
+ horizontalTranslation.stretchTo(horizontalTranslationStretch)
+ }
+
+ fun resetStretch() {
+ setStretch(0f, 0f, 0f, 0f, 0f, 0f, 0f)
+ }
+
+ /**
+ * Updates resting arrow and background size not accounting for stretch
+ */
+ internal fun updateRestingArrowDimens(
+ backgroundWidth: Float,
+ backgroundHeight: Float,
+ backgroundEdgeCornerRadius: Float,
+ backgroundDragCornerRadius: Float,
+ arrowLength: Float,
+ arrowHeight: Float,
+ horizontalTranslation: Float,
+ animate: Boolean
+ ) {
+ this.arrowLength.updateRestingPosition(arrowLength, animate)
+ this.arrowHeight.updateRestingPosition(arrowHeight, animate)
+ this.backgroundWidth.updateRestingPosition(backgroundWidth, animate)
+ this.backgroundHeight.updateRestingPosition(backgroundHeight, animate)
+ this.backgroundEdgeCornerRadius.updateRestingPosition(backgroundEdgeCornerRadius, animate)
+ this.backgroundDragCornerRadius.updateRestingPosition(backgroundDragCornerRadius, animate)
+ this.horizontalTranslation.updateRestingPosition(horizontalTranslation, animate)
+ }
+
+ fun animateVertically(yPos: Float) = verticalTranslation.stretchTo(yPos)
+
+ fun setArrowStiffness(arrowStiffness: Float, arrowDampingRatio: Float) {
+ arrowLength.animation.spring.apply {
+ stiffness = arrowStiffness
+ dampingRatio = arrowDampingRatio
+ }
+ arrowHeight.animation.spring.apply {
+ stiffness = arrowStiffness
+ dampingRatio = arrowDampingRatio
+ }
+ }
+
+ override fun hasOverlappingRendering() = false
+
+ override fun onDraw(canvas: Canvas) {
+ var edgeCorner = backgroundEdgeCornerRadius.pos
+ val farCorner = backgroundDragCornerRadius.pos
+ val halfHeight = backgroundHeight.pos / 2
+
+ canvas.save()
+
+ if (!isLeftPanel) canvas.scale(-1f, 1f, width / 2.0f, 0f)
+
+ canvas.translate(
+ horizontalTranslation.pos,
+ height * 0.5f + verticalTranslation.pos
+ )
+
+ val arrowBackground = arrowBackgroundRect.apply {
+ left = 0f
+ top = -halfHeight
+ right = backgroundWidth.pos
+ bottom = halfHeight
+ }.toPathWithRoundCorners(
+ topLeft = edgeCorner,
+ bottomLeft = edgeCorner,
+ topRight = farCorner,
+ bottomRight = farCorner
+ )
+ canvas.drawPath(arrowBackground, arrowBackgroundPaint)
+
+ val dx = arrowLength.pos
+ val dy = arrowHeight.pos
+
+ // How far the arrow bounding box should be from the edge of the screen. Measured from
+ // either the tip or the back of the arrow, whichever is closer
+ var arrowOffset = (backgroundWidth.pos - dx) / 2
+ canvas.translate(
+ /* dx= */ arrowOffset,
+ /* dy= */ 0f /* pass 0 for the y position since the canvas was already translated */
+ )
+
+ val arrowPointsAwayFromEdge = !arrowsPointLeft.xor(isLeftPanel)
+ if (arrowPointsAwayFromEdge) {
+ canvas.apply {
+ scale(-1f, 1f, 0f, 0f)
+ translate(-dx, 0f)
+ }
+ }
+
+ val arrowPath = calculateArrowPath(dx = dx, dy = dy)
+ canvas.drawPath(arrowPath, arrowPaint)
+ canvas.restore()
+
+ if (trackingBackArrowLatency) {
+ latencyTracker.onActionEnd(LatencyTracker.ACTION_SHOW_BACK_ARROW)
+ trackingBackArrowLatency = false
+ }
+
+ if (DEBUG) drawDebugInfo?.invoke(canvas)
+ }
+
+ fun startTrackingShowBackArrowLatency() {
+ latencyTracker.onActionStart(LatencyTracker.ACTION_SHOW_BACK_ARROW)
+ trackingBackArrowLatency = true
+ }
+
+ private fun RectF.toPathWithRoundCorners(
+ topLeft: Float = 0f,
+ topRight: Float = 0f,
+ bottomRight: Float = 0f,
+ bottomLeft: Float = 0f
+ ): Path = Path().apply {
+ val corners = floatArrayOf(
+ topLeft, topLeft,
+ topRight, topRight,
+ bottomRight, bottomRight,
+ bottomLeft, bottomLeft
+ )
+ addRoundRect(this@toPathWithRoundCorners, corners, Path.Direction.CW)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
new file mode 100644
index 000000000000..100411b1cb93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2022 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.navigationbar.gestural
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Point
+import android.os.Handler
+import android.os.SystemClock
+import android.os.VibrationEffect
+import android.util.Log
+import android.util.MathUtils.constrain
+import android.util.MathUtils.saturate
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.View
+import android.view.WindowManager
+import android.view.animation.AccelerateInterpolator
+import android.view.animation.PathInterpolator
+import android.window.BackEvent
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.internal.util.LatencyTracker
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.NavigationEdgeBackPlugin
+import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.ViewController
+import com.android.wm.shell.back.BackAnimation
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.sign
+
+private const val TAG = "BackPanelController"
+private const val DEBUG = false
+
+private const val ENABLE_FAILSAFE = true
+
+private const val FAILSAFE_DELAY_MS: Long = 350
+
+/**
+ * The time required between the arrow-appears vibration effect and the back-committed vibration
+ * effect. If the arrow is flung quickly, the phone only vibrates once. However, if the arrow is
+ * held on the screen for a long time, it will vibrate a second time when the back gesture is
+ * committed.
+ */
+private const val GESTURE_DURATION_FOR_CLICK_MS = 400
+
+/**
+ * The min duration arrow remains on screen during a fling event.
+ */
+private const val FLING_PAUSE_DURATION_MS = 50L
+
+/**
+ * The min duration arrow remains on screen during a fling event.
+ */
+private const val MIN_FLING_VELOCITY = 3000
+
+/**
+ * The amount of rubber banding we do for the vertical translation
+ */
+private const val RUBBER_BAND_AMOUNT = 15
+
+private const val ARROW_APPEAR_STIFFNESS = 600f
+private const val ARROW_APPEAR_DAMPING_RATIO = 0.4f
+private const val ARROW_DISAPPEAR_STIFFNESS = 1200f
+private const val ARROW_DISAPPEAR_DAMPING_RATIO = SpringForce.DAMPING_RATIO_NO_BOUNCY
+
+/**
+ * The interpolator used to rubber band
+ */
+private val RUBBER_BAND_INTERPOLATOR = PathInterpolator(1.0f / 5.0f, 1.0f, 1.0f, 1.0f)
+
+private val ACCELERATE_INTERPOLATOR = AccelerateInterpolator(0.7f)
+
+class BackPanelController private constructor(
+ context: Context,
+ private var backAnimation: BackAnimation?,
+ private val windowManager: WindowManager,
+ @Main private val mainHandler: Handler,
+ private val vibratorHelper: VibratorHelper,
+ private val configurationController: ConfigurationController,
+ latencyTracker: LatencyTracker
+) : ViewController<BackPanel>(BackPanel(context, latencyTracker)), NavigationEdgeBackPlugin {
+
+ /**
+ * Injectable instance to create a new BackPanelController.
+ *
+ * Necessary because EdgeBackGestureHandler sometimes needs to create new instances of
+ * BackPanelController, and we need to match EdgeBackGestureHandler's context.
+ */
+ class Factory @Inject constructor(
+ private val windowManager: WindowManager,
+ @Main private val mainHandler: Handler,
+ private val vibratorHelper: VibratorHelper,
+ private val configurationController: ConfigurationController,
+ private val latencyTracker: LatencyTracker
+ ) {
+ /** Construct a [BackPanelController]. */
+ fun create(context: Context, backAnimation: BackAnimation?): BackPanelController {
+ val backPanelController = BackPanelController(
+ context,
+ backAnimation,
+ windowManager,
+ mainHandler,
+ vibratorHelper,
+ configurationController,
+ latencyTracker
+ )
+ backPanelController.init()
+ return backPanelController
+ }
+ }
+
+ private var params: EdgePanelParams = EdgePanelParams(resources)
+ private var currentState: GestureState = GestureState.GONE
+ private var previousState: GestureState = GestureState.GONE
+
+ // Phone should only vibrate the first time the arrow is activated
+ private var hasHapticPlayed = false
+
+ // Screen attributes
+ private lateinit var layoutParams: WindowManager.LayoutParams
+ private val displaySize = Point()
+
+ private lateinit var backCallback: NavigationEdgeBackPlugin.BackCallback
+
+ private var previousXTranslation = 0f
+ private var totalTouchDelta = 0f
+ private var velocityTracker: VelocityTracker? = null
+ set(value) {
+ if (field != value) field?.recycle()
+ field = value
+ }
+ get() {
+ if (field == null) field = VelocityTracker.obtain()
+ return field
+ }
+
+ // The x,y position of the first touch event
+ private var startX = 0f
+ private var startY = 0f
+
+ private val failsafeRunnable = Runnable { onFailsafe() }
+
+ private enum class GestureState {
+ /* Arrow is off the screen and invisible */
+ GONE,
+
+ /* Arrow is animating in */
+ ENTRY,
+
+ /* could be entry, neutral, or stretched, releasing will commit back */
+ ACTIVE,
+
+ /* releasing will cancel back */
+ INACTIVE,
+
+ /* like committed, but animation takes longer */
+ FLUNG,
+
+ /* back action currently occurring, arrow soon to be GONE */
+ COMMITTED,
+
+ /* back action currently cancelling, arrow soon to be GONE */
+ CANCELLED
+ }
+
+ /**
+ * Wrapper around OnAnimationEndListener which runs the given runnable after a delay. The
+ * runnable is not called if the animation is cancelled
+ */
+ class DelayedOnAnimationEndListener(
+ private val handler: Handler,
+ private val runnable: Runnable,
+ private val delay: Long
+ ) : DynamicAnimation.OnAnimationEndListener {
+
+ override fun onAnimationEnd(
+ animation: DynamicAnimation<*>,
+ canceled: Boolean,
+ value: Float,
+ velocity: Float
+ ) {
+ animation.removeEndListener(this)
+ if (!canceled) {
+ handler.postDelayed(runnable, delay)
+ }
+ }
+
+ fun runNow() {
+ runnable.run()
+ }
+ }
+
+ private val setCommittedEndListener =
+ DelayedOnAnimationEndListener(
+ mainHandler,
+ { updateArrowState(GestureState.COMMITTED) },
+ delay = FLING_PAUSE_DURATION_MS
+ )
+
+ private val setGoneEndListener =
+ DelayedOnAnimationEndListener(
+ mainHandler,
+ {
+ cancelFailsafe()
+ updateArrowState(GestureState.GONE)
+ },
+ delay = 0
+ )
+
+ // Vibration
+ private var vibrationTime: Long = 0
+
+ // Minimum size of the screen's width or height
+ private var screenSize = 0
+
+ /**
+ * Used for initialization and configuration changes
+ */
+ private fun updateConfiguration() {
+ params.update(resources)
+ initializeBackAnimation()
+ mView.updateArrowPaint(params.arrowThickness)
+ }
+
+ private val configurationListener = object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateConfiguration()
+ }
+
+ override fun onLayoutDirectionChanged(isLayoutRtl: Boolean) {
+ updateArrowDirection(isLayoutRtl)
+ }
+ }
+
+ override fun onViewAttached() {
+ updateConfiguration()
+ updateArrowDirection(configurationController.isLayoutRtl)
+ updateArrowState(GestureState.GONE, force = true)
+ updateRestingArrowDimens(animated = false, currentState)
+ configurationController.addCallback(configurationListener)
+ }
+
+ /** Update the arrow direction. The arrow should point the same way for both panels. */
+ private fun updateArrowDirection(isLayoutRtl: Boolean) {
+ mView.arrowsPointLeft = isLayoutRtl
+ }
+
+ override fun onViewDetached() {
+ configurationController.removeCallback(configurationListener)
+ }
+
+ override fun onMotionEvent(event: MotionEvent) {
+ backAnimation?.onBackMotion(
+ event,
+ event.actionMasked,
+ if (mView.isLeftPanel) BackEvent.EDGE_LEFT else BackEvent.EDGE_RIGHT
+ )
+
+ velocityTracker!!.addMovement(event)
+ when (event.actionMasked) {
+ MotionEvent.ACTION_DOWN -> {
+ resetOnDown()
+ startX = event.x
+ startY = event.y
+
+ // Reset the arrow to the side
+ updateArrowState(GestureState.ENTRY)
+
+ windowManager.updateViewLayout(mView, layoutParams)
+ mView.startTrackingShowBackArrowLatency()
+ }
+ MotionEvent.ACTION_MOVE -> handleMoveEvent(event)
+ MotionEvent.ACTION_UP -> {
+ if (currentState == GestureState.ACTIVE) {
+ updateArrowState(if (isFlung()) GestureState.FLUNG else GestureState.COMMITTED)
+ } else {
+ updateArrowState(GestureState.CANCELLED)
+ }
+ velocityTracker = null
+ }
+ MotionEvent.ACTION_CANCEL -> {
+ updateArrowState(GestureState.CANCELLED)
+ velocityTracker = null
+ }
+ }
+ }
+
+ private fun updateArrowStateOnMove(yTranslation: Float, xTranslation: Float) {
+ when (currentState) {
+ GestureState.GONE, GestureState.FLUNG, GestureState.COMMITTED, GestureState.CANCELLED ->
+ return
+ }
+
+ updateArrowState(
+ when {
+ // Check if we should transition from ENTRY to ACTIVE
+ currentState == GestureState.ENTRY && xTranslation > params.swipeTriggerThreshold ->
+ GestureState.ACTIVE
+
+ // Abort if we had continuous motion toward the edge for a while, OR the direction
+ // in Y is bigger than X * 2
+ currentState == GestureState.ACTIVE &&
+ ((totalTouchDelta < 0 && -totalTouchDelta > params.minDeltaForSwitch) ||
+ (yTranslation > xTranslation * 2)) ->
+ GestureState.INACTIVE
+
+ // Re-activate if we had continuous motion away from the edge for a while
+ currentState == GestureState.INACTIVE &&
+ (totalTouchDelta > 0 && totalTouchDelta > params.minDeltaForSwitch) ->
+ GestureState.ACTIVE
+
+ // By default assume the current direction is kept
+ else -> currentState
+ }
+ )
+ }
+
+ private fun handleMoveEvent(event: MotionEvent) {
+ when (currentState) {
+ GestureState.GONE, GestureState.FLUNG, GestureState.COMMITTED,
+ GestureState.CANCELLED -> return
+ }
+
+ val x = event.x
+ val y = event.y
+
+ val yOffset = y - startY
+
+ // How far in the y direction we are from the original touch
+ val yTranslation = abs(yOffset)
+
+ // How far in the x direction we are from the original touch ignoring motion that
+ // occurs between the screen edge and the touch start.
+ val xTranslation = max(0f, if (mView.isLeftPanel) x - startX else startX - x)
+
+ // Compared to last time, how far we moved in the x direction. If <0, we are moving closer
+ // to the edge. If >0, we are moving further from the edge
+ val xDelta = xTranslation - previousXTranslation
+ previousXTranslation = xTranslation
+
+ if (abs(xDelta) > 0) {
+ if (sign(xDelta) == sign(totalTouchDelta)) {
+ // Direction has NOT changed, so keep counting the delta
+ totalTouchDelta += xDelta
+ } else {
+ // Direction has changed, so reset the delta
+ totalTouchDelta = xDelta
+ }
+ }
+
+ updateArrowStateOnMove(yTranslation, xTranslation)
+ when (currentState) {
+ GestureState.ACTIVE -> setActiveStretch(fullScreenStretchProgress(xTranslation))
+ GestureState.ENTRY ->
+ setEntryStretch(preThresholdStretchProgress(xTranslation))
+ GestureState.INACTIVE -> mView.resetStretch()
+ }
+
+ // set y translation
+ setVerticalTranslation(yOffset)
+ }
+
+ fun setVerticalTranslation(yOffset: Float) {
+ val yTranslation = abs(yOffset)
+ val maxYOffset = (mView.height / 2) - (params.entryBackgroundHeight / 2)
+ val yProgress = saturate(yTranslation / (maxYOffset * RUBBER_BAND_AMOUNT))
+ mView.animateVertically(
+ RUBBER_BAND_INTERPOLATOR.getInterpolation(yProgress) * maxYOffset * sign(
+ yOffset
+ )
+ )
+ }
+
+ /**
+ * @return the relative position of the drag from the time after the arrow is activated until
+ * the arrow is fully stretched (between 0.0 - 1.0f)
+ */
+ fun fullScreenStretchProgress(xTranslation: Float): Float {
+ return saturate(
+ (xTranslation - params.swipeTriggerThreshold) /
+ (min(
+ params.fullyStretchedThreshold,
+ screenSize.toFloat()
+ ) - params.swipeTriggerThreshold)
+ )
+ }
+
+ /**
+ * Tracks the relative position of the drag from the entry until the threshold where the arrow
+ * activates (between 0.0 - 1.0f)
+ */
+ fun preThresholdStretchProgress(xTranslation: Float): Float {
+ return saturate(xTranslation / params.swipeTriggerThreshold)
+ }
+
+ fun setActiveStretch(progress: Float) {
+ val stretch = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
+ mView.setStretch(
+ arrowLengthStretch = stretch * (params.stretchedArrowLength - params.activeArrowLength),
+ arrowHeightStretch = stretch * (params.stretchedArrowHeight - params.activeArrowHeight),
+ backgroundWidthStretch =
+ stretch * (params.stretchBackgroundWidth - params.activeBackgroundWidth),
+ backgroundHeightStretch =
+ stretch * (params.stretchBackgroundHeight - params.activeBackgroundHeight),
+ backgroundEdgeCornerRadiusStretch =
+ stretch * (params.stretchEdgeCorners - params.activeEdgeCorners),
+ backgroundDragCornerRadiusStretch =
+ stretch * (params.stretchFarCorners - params.activeFarCorners),
+ horizontalTranslationStretch = stretch * (params.stretchMargin - params.activeMargin)
+ )
+ }
+
+ fun setEntryStretch(progress: Float) {
+ val bgStretch = ACCELERATE_INTERPOLATOR.getInterpolation(progress)
+ val arrowStretch = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
+ mView.setStretch(
+ arrowLengthStretch =
+ arrowStretch * (params.activeArrowLength - params.entryArrowLength),
+ arrowHeightStretch =
+ arrowStretch * (params.activeArrowHeight - params.entryArrowHeight),
+ backgroundWidthStretch =
+ bgStretch * (params.preThresholdBackgroundWidth - params.entryBackgroundWidth),
+ backgroundHeightStretch =
+ bgStretch * (params.preThresholdBackgroundHeight - params.entryBackgroundHeight),
+ backgroundEdgeCornerRadiusStretch =
+ bgStretch * (params.preThresholdEdgeCorners - params.entryEdgeCorners),
+ backgroundDragCornerRadiusStretch =
+ bgStretch * (params.preThresholdFarCorners - params.entryFarCorners),
+ horizontalTranslationStretch =
+ bgStretch * (params.preThresholdMargin - params.entryMargin)
+ )
+ }
+
+ fun setBackAnimation(backAnimation: BackAnimation?) {
+ this.backAnimation = backAnimation
+ initializeBackAnimation()
+ }
+
+ private fun initializeBackAnimation() {
+ backAnimation?.setSwipeThresholds(
+ params.swipeTriggerThreshold,
+ params.swipeProgressThreshold
+ )
+ }
+
+ override fun onDestroy() {
+ cancelFailsafe()
+ windowManager.removeView(mView)
+ }
+
+ override fun setIsLeftPanel(isLeftPanel: Boolean) {
+ mView.isLeftPanel = isLeftPanel
+ layoutParams.gravity = if (isLeftPanel) {
+ Gravity.LEFT or Gravity.TOP
+ } else {
+ Gravity.RIGHT or Gravity.TOP
+ }
+ }
+
+ override fun setInsets(insetLeft: Int, insetRight: Int) {
+ }
+
+ override fun setBackCallback(callback: NavigationEdgeBackPlugin.BackCallback) {
+ backCallback = callback
+ }
+
+ override fun setLayoutParams(layoutParams: WindowManager.LayoutParams) {
+ this.layoutParams = layoutParams
+ windowManager.addView(mView, layoutParams)
+ }
+
+ private fun isFlung() = velocityTracker!!.run {
+ computeCurrentVelocity(1000)
+ abs(xVelocity) > MIN_FLING_VELOCITY
+ }
+
+ private fun playFlingBackAnimation() {
+ playAnimation(setCommittedEndListener)
+ }
+
+ private fun playCommitBackAnimation() {
+ // Check if we should vibrate again
+ if (previousState != GestureState.FLUNG) {
+ backCallback.triggerBack()
+ velocityTracker!!.computeCurrentVelocity(1000)
+ val isSlow = abs(velocityTracker!!.xVelocity) < 500
+ val hasNotVibratedRecently =
+ SystemClock.uptimeMillis() - vibrationTime >= GESTURE_DURATION_FOR_CLICK_MS
+ if (isSlow || hasNotVibratedRecently) {
+ vibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK)
+ }
+ }
+ playAnimation(setGoneEndListener)
+ }
+
+ private fun playCancelBackAnimation() {
+ backCallback.cancelBack()
+ playAnimation(setGoneEndListener)
+ }
+
+ /**
+ * @return true if the animation is running, false otherwise. Some transitions don't animate
+ */
+ private fun playAnimation(endListener: DelayedOnAnimationEndListener) {
+ updateRestingArrowDimens(animated = true, currentState)
+
+ if (!mView.addEndListener(endListener)) {
+ scheduleFailsafe()
+ }
+ }
+
+ private fun resetOnDown() {
+ hasHapticPlayed = false
+ totalTouchDelta = 0f
+ vibrationTime = 0
+ cancelFailsafe()
+ backAnimation?.setTriggerBack(false)
+ }
+
+ private fun updateYPosition(touchY: Float) {
+ var yPosition = touchY - params.fingerOffset
+ yPosition = Math.max(yPosition, params.minArrowYPosition.toFloat())
+ yPosition -= layoutParams.height / 2.0f
+ layoutParams.y = constrain(yPosition.toInt(), 0, displaySize.y)
+ }
+
+ override fun setDisplaySize(displaySize: Point) {
+ this.displaySize.set(displaySize.x, displaySize.y)
+ screenSize = Math.min(displaySize.x, displaySize.y)
+ }
+
+ /**
+ * Updates resting arrow and background size not accounting for stretch
+ */
+ private fun updateRestingArrowDimens(animated: Boolean, currentState: GestureState) {
+ mView.updateRestingArrowDimens(
+ backgroundWidth =
+ when (currentState) {
+ GestureState.GONE, GestureState.ENTRY -> params.entryBackgroundWidth
+ else -> params.activeBackgroundWidth
+ },
+ backgroundHeight =
+ when (currentState) {
+ GestureState.GONE, GestureState.ENTRY -> params.entryBackgroundHeight
+ else -> params.activeBackgroundHeight
+ },
+ backgroundEdgeCornerRadius =
+ when (currentState) {
+ GestureState.GONE, GestureState.ENTRY, GestureState.INACTIVE ->
+ params.entryEdgeCorners
+ else ->
+ params.activeEdgeCorners
+ },
+ backgroundDragCornerRadius =
+ when (currentState) {
+ GestureState.GONE, GestureState.ENTRY -> params.entryFarCorners
+ else -> params.activeFarCorners
+ },
+ arrowLength =
+ when (currentState) {
+ GestureState.ACTIVE, GestureState.INACTIVE, GestureState.COMMITTED,
+ GestureState.FLUNG -> params.activeArrowLength
+ GestureState.CANCELLED -> params.cancelledArrowLength
+ GestureState.GONE, GestureState.ENTRY -> params.entryArrowLength
+ },
+ arrowHeight =
+ when (currentState) {
+ GestureState.ACTIVE, GestureState.INACTIVE, GestureState.COMMITTED,
+ GestureState.FLUNG -> params.activeArrowHeight
+ GestureState.CANCELLED -> params.cancelledArrowHeight
+ GestureState.GONE, GestureState.ENTRY -> params.entryArrowHeight
+ },
+ horizontalTranslation =
+ when (currentState) {
+ GestureState.GONE -> -params.activeBackgroundWidth
+ // Position the cancelled/committed arrow slightly further off the screen so we
+ // do not see part of it bouncing
+ GestureState.CANCELLED, GestureState.COMMITTED ->
+ -params.activeBackgroundWidth * 1.5f
+ GestureState.FLUNG -> params.stretchMargin
+ GestureState.ACTIVE -> params.activeMargin
+ GestureState.ENTRY, GestureState.INACTIVE -> params.entryMargin
+ },
+ animate = animated
+ )
+ if (animated) {
+ when (currentState) {
+ GestureState.ENTRY, GestureState.ACTIVE, GestureState.FLUNG ->
+ mView.setArrowStiffness(ARROW_APPEAR_STIFFNESS, ARROW_APPEAR_DAMPING_RATIO)
+ else ->
+ mView.setArrowStiffness(
+ ARROW_DISAPPEAR_STIFFNESS, ARROW_DISAPPEAR_DAMPING_RATIO)
+ }
+ }
+ }
+
+ /**
+ * Update arrow state. If state has not changed, this is a no-op.
+ *
+ * Transitioning to active/inactive will indicate whether or not releasing touch will trigger
+ * the back action.
+ */
+ private fun updateArrowState(newState: GestureState, force: Boolean = false) {
+ if (!force && currentState == newState) return
+
+ if (DEBUG) Log.d(TAG, "updateArrowState $currentState -> $newState")
+ previousState = currentState
+ currentState = newState
+ mView.visibility = if (currentState == GestureState.GONE) View.GONE else View.VISIBLE
+
+ when (currentState) {
+ // Transitioning to GONE never animates since the arrow is (presumably) already off the
+ // screen
+ GestureState.GONE -> updateRestingArrowDimens(animated = false, currentState)
+ GestureState.ENTRY -> {
+ updateYPosition(startY)
+ updateRestingArrowDimens(animated = true, currentState)
+ }
+ GestureState.ACTIVE -> {
+ backAnimation?.setTriggerBack(true)
+ updateRestingArrowDimens(animated = true, currentState)
+ // Vibrate the first time we transition to ACTIVE
+ if (!hasHapticPlayed) {
+ hasHapticPlayed = true
+ vibrationTime = SystemClock.uptimeMillis()
+ vibratorHelper.vibrate(VibrationEffect.EFFECT_TICK)
+ }
+ }
+ GestureState.INACTIVE -> {
+ backAnimation?.setTriggerBack(false)
+ updateRestingArrowDimens(animated = true, currentState)
+ }
+ GestureState.FLUNG -> playFlingBackAnimation()
+ GestureState.COMMITTED -> playCommitBackAnimation()
+ GestureState.CANCELLED -> playCancelBackAnimation()
+ }
+ }
+
+ private fun scheduleFailsafe() {
+ if (!ENABLE_FAILSAFE) return
+ cancelFailsafe()
+ if (DEBUG) Log.d(TAG, "scheduleFailsafe")
+ mainHandler.postDelayed(failsafeRunnable, FAILSAFE_DELAY_MS)
+ }
+
+ private fun cancelFailsafe() {
+ if (DEBUG) Log.d(TAG, "cancelFailsafe")
+ mainHandler.removeCallbacks(failsafeRunnable)
+ }
+
+ private fun onFailsafe() {
+ if (DEBUG) Log.d(TAG, "onFailsafe")
+ updateArrowState(GestureState.GONE, force = true)
+ }
+
+ override fun dump(pw: PrintWriter) {
+ pw.println("$TAG:")
+ pw.println(" currentState=$currentState")
+ pw.println(" isLeftPanel=$mView.isLeftPanel")
+ }
+
+ init {
+ if (DEBUG) mView.drawDebugInfo = { canvas ->
+ val debugStrings = listOf(
+ "$currentState",
+ "startX=$startX",
+ "startY=$startY",
+ "xDelta=${"%.1f".format(totalTouchDelta)}",
+ "xTranslation=${"%.1f".format(previousXTranslation)}",
+ "pre=${"%.0f".format(preThresholdStretchProgress(previousXTranslation) * 100)}%",
+ "post=${"%.0f".format(fullScreenStretchProgress(previousXTranslation) * 100)}%"
+ )
+ val debugPaint = Paint().apply {
+ color = Color.WHITE
+ }
+ val debugInfoBottom = debugStrings.size * 32f + 4f
+ canvas.drawRect(
+ 4f,
+ 4f,
+ canvas.width.toFloat(),
+ debugStrings.size * 32f + 4f,
+ debugPaint
+ )
+ debugPaint.apply {
+ color = Color.BLACK
+ textSize = 32f
+ }
+ var offset = 32f
+ for (debugText in debugStrings) {
+ canvas.drawText(debugText, 10f, offset, debugPaint)
+ offset += 32f
+ }
+ debugPaint.apply {
+ color = Color.RED
+ style = Paint.Style.STROKE
+ strokeWidth = 4f
+ }
+ val canvasWidth = canvas.width.toFloat()
+ val canvasHeight = canvas.height.toFloat()
+ canvas.drawRect(0f, 0f, canvasWidth, canvasHeight, debugPaint)
+
+ fun drawVerticalLine(x: Float, color: Int) {
+ debugPaint.color = color
+ val x = if (mView.isLeftPanel) x else canvasWidth - x
+ canvas.drawLine(x, debugInfoBottom, x, canvas.height.toFloat(), debugPaint)
+ }
+
+ drawVerticalLine(x = params.swipeTriggerThreshold, color = Color.BLUE)
+ drawVerticalLine(x = startX, color = Color.GREEN)
+ drawVerticalLine(x = previousXTranslation, color = Color.DKGRAY)
+ }
+ }
+}
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 ea41fe74f798..d41837b7cf4d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -62,6 +62,8 @@ import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -182,6 +184,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private final PluginManager mPluginManager;
private final ProtoTracer mProtoTracer;
private final NavigationModeController mNavigationModeController;
+ private final BackPanelController.Factory mBackPanelControllerFactory;
private final ViewConfiguration mViewConfiguration;
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
@@ -199,6 +202,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private final Region mExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
private final LatencyTracker mLatencyTracker;
+ private final FeatureFlags mFeatureFlags;
// The left side edge width where touch down is allowed
private int mEdgeWidthLeft;
@@ -230,6 +234,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private boolean mIsBackGestureAllowed;
private boolean mGestureBlockingActivityRunning;
private boolean mIsInPipMode;
+ private boolean mIsPredictiveBackAnimEnabled;
private InputMonitor mInputMonitor;
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
@@ -298,12 +303,22 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
};
- EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService,
- SysUiState sysUiState, PluginManager pluginManager, @Main Executor executor,
- BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
- NavigationModeController navigationModeController, ViewConfiguration viewConfiguration,
- WindowManager windowManager, IWindowManager windowManagerService,
- FalsingManager falsingManager, LatencyTracker latencyTracker) {
+ EdgeBackGestureHandler(
+ Context context,
+ OverviewProxyService overviewProxyService,
+ SysUiState sysUiState,
+ PluginManager pluginManager,
+ @Main Executor executor,
+ BroadcastDispatcher broadcastDispatcher,
+ ProtoTracer protoTracer,
+ NavigationModeController navigationModeController,
+ BackPanelController.Factory backPanelControllerFactory,
+ ViewConfiguration viewConfiguration,
+ WindowManager windowManager,
+ IWindowManager windowManagerService,
+ FalsingManager falsingManager,
+ LatencyTracker latencyTracker,
+ FeatureFlags featureFlags) {
super(broadcastDispatcher);
mContext = context;
mDisplayId = context.getDisplayId();
@@ -313,11 +328,13 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
mPluginManager = pluginManager;
mProtoTracer = protoTracer;
mNavigationModeController = navigationModeController;
+ mBackPanelControllerFactory = backPanelControllerFactory;
mViewConfiguration = viewConfiguration;
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mFalsingManager = falsingManager;
mLatencyTracker = latencyTracker;
+ mFeatureFlags = featureFlags;
ComponentName recentsComponentName = ComponentName.unflattenFromString(
context.getString(com.android.internal.R.string.config_recentsComponentName));
if (recentsComponentName != null) {
@@ -507,8 +524,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
Choreographer.getInstance(), this::onInputEvent);
// Add a nav bar panel window
- setEdgeBackPlugin(
- new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
+ mIsPredictiveBackAnimEnabled =
+ mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_ANIM);
+ resetEdgeBackPlugin();
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
}
@@ -523,7 +541,17 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
@Override
public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
- setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
+ resetEdgeBackPlugin();
+ }
+
+ private void resetEdgeBackPlugin() {
+ if (mIsPredictiveBackAnimEnabled) {
+ setEdgeBackPlugin(
+ mBackPanelControllerFactory.create(mContext, mBackAnimation));
+ } else {
+ setEdgeBackPlugin(
+ new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
+ }
}
private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
@@ -948,8 +976,12 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
public void setBackAnimation(BackAnimation backAnimation) {
mBackAnimation = backAnimation;
- if (mEdgeBackPlugin != null && mEdgeBackPlugin instanceof NavigationBarEdgePanel) {
- ((NavigationBarEdgePanel) mEdgeBackPlugin).setBackAnimation(backAnimation);
+ if (mEdgeBackPlugin != null) {
+ if (mEdgeBackPlugin instanceof NavigationBarEdgePanel) {
+ ((NavigationBarEdgePanel) mEdgeBackPlugin).setBackAnimation(backAnimation);
+ } else if (mEdgeBackPlugin instanceof BackPanelController) {
+ ((BackPanelController) mEdgeBackPlugin).setBackAnimation(backAnimation);
+ }
}
}
@@ -967,20 +999,29 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private final BroadcastDispatcher mBroadcastDispatcher;
private final ProtoTracer mProtoTracer;
private final NavigationModeController mNavigationModeController;
+ private final BackPanelController.Factory mBackPanelControllerFactory;
private final ViewConfiguration mViewConfiguration;
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
private final FalsingManager mFalsingManager;
private final LatencyTracker mLatencyTracker;
+ private final FeatureFlags mFeatureFlags;
@Inject
public Factory(OverviewProxyService overviewProxyService,
- SysUiState sysUiState, PluginManager pluginManager, @Main Executor executor,
- BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
- NavigationModeController navigationModeController,
- ViewConfiguration viewConfiguration, WindowManager windowManager,
- IWindowManager windowManagerService, FalsingManager falsingManager,
- LatencyTracker latencyTracker) {
+ SysUiState sysUiState,
+ PluginManager pluginManager,
+ @Main Executor executor,
+ BroadcastDispatcher broadcastDispatcher,
+ ProtoTracer protoTracer,
+ NavigationModeController navigationModeController,
+ BackPanelController.Factory backPanelControllerFactory,
+ ViewConfiguration viewConfiguration,
+ WindowManager windowManager,
+ IWindowManager windowManagerService,
+ FalsingManager falsingManager,
+ LatencyTracker latencyTracker,
+ FeatureFlags featureFlags) {
mOverviewProxyService = overviewProxyService;
mSysUiState = sysUiState;
mPluginManager = pluginManager;
@@ -988,19 +1029,33 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
mBroadcastDispatcher = broadcastDispatcher;
mProtoTracer = protoTracer;
mNavigationModeController = navigationModeController;
+ mBackPanelControllerFactory = backPanelControllerFactory;
mViewConfiguration = viewConfiguration;
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mFalsingManager = falsingManager;
mLatencyTracker = latencyTracker;
+ mFeatureFlags = featureFlags;
}
/** Construct a {@link EdgeBackGestureHandler}. */
public EdgeBackGestureHandler create(Context context) {
- return new EdgeBackGestureHandler(context, mOverviewProxyService, mSysUiState,
- mPluginManager, mExecutor, mBroadcastDispatcher, mProtoTracer,
- mNavigationModeController, mViewConfiguration, mWindowManager,
- mWindowManagerService, mFalsingManager, mLatencyTracker);
+ return new EdgeBackGestureHandler(
+ context,
+ mOverviewProxyService,
+ mSysUiState,
+ mPluginManager,
+ mExecutor,
+ mBroadcastDispatcher,
+ mProtoTracer,
+ mNavigationModeController,
+ mBackPanelControllerFactory,
+ mViewConfiguration,
+ mWindowManager,
+ mWindowManagerService,
+ mFalsingManager,
+ mLatencyTracker,
+ mFeatureFlags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
new file mode 100644
index 000000000000..51566b0f8393
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
@@ -0,0 +1,139 @@
+package com.android.systemui.navigationbar.gestural
+
+import android.content.res.Resources
+import com.android.systemui.R
+
+data class EdgePanelParams(private var resources: Resources) {
+ var arrowThickness: Float = 0f
+ private set
+ var entryArrowLength: Float = 0f
+ private set
+ var entryArrowHeight: Float = 0f
+ private set
+ var activeArrowLength: Float = 0f
+ private set
+ var activeArrowHeight: Float = 0f
+ private set
+ var stretchedArrowLength: Float = 0f
+ private set
+ var stretchedArrowHeight: Float = 0f
+ private set
+ var cancelledArrowLength: Float = 0f
+ private set
+ var cancelledArrowHeight: Float = 0f
+ private set
+ var entryMargin: Float = 0f
+ private set
+ var entryBackgroundWidth: Float = 0f
+ private set
+ var entryBackgroundHeight: Float = 0f
+ private set
+ var entryEdgeCorners: Float = 0f
+ private set
+ var entryFarCorners: Float = 0f
+ private set
+ var preThresholdMargin: Float = 0f
+ private set
+ var preThresholdBackgroundWidth: Float = 0f
+ private set
+ var preThresholdBackgroundHeight: Float = 0f
+ private set
+ var preThresholdEdgeCorners: Float = 0f
+ private set
+ var preThresholdFarCorners: Float = 0f
+ private set
+ var activeMargin: Float = 0f
+ private set
+ var activeBackgroundWidth: Float = 0f
+ private set
+ var activeBackgroundHeight: Float = 0f
+ private set
+ var activeEdgeCorners: Float = 0f
+ private set
+ var activeFarCorners: Float = 0f
+ private set
+ var fullyStretchedThreshold: Float = 0f
+ private set
+ var stretchMargin: Float = 0f
+ private set
+ var stretchBackgroundWidth: Float = 0f
+ private set
+ var stretchBackgroundHeight: Float = 0f
+ private set
+ var stretchEdgeCorners: Float = 0f
+ private set
+ var stretchFarCorners: Float = 0f
+ private set
+
+ // navigation bar edge constants
+ var arrowPaddingEnd: Int = 0
+ private set
+
+ // The closest to y
+ var minArrowYPosition: Int = 0
+ private set
+ var fingerOffset: Int = 0
+ private set
+ var swipeTriggerThreshold: Float = 0f
+ private set
+ var swipeProgressThreshold: Float = 0f
+ private set
+
+ // The minimum delta needed to change direction / stop triggering back
+ var minDeltaForSwitch: Int = 0
+ private set
+
+ init {
+ update(resources)
+ }
+
+ private fun getDimen(id: Int): Float {
+ return resources.getDimension(id)
+ }
+
+ private fun getPx(id: Int): Int {
+ return resources.getDimensionPixelSize(id)
+ }
+
+ fun update(resources: Resources) {
+ this.resources = resources
+ arrowThickness = getDimen(R.dimen.navigation_edge_arrow_thickness)
+ entryArrowLength = getDimen(R.dimen.navigation_edge_entry_arrow_length)
+ entryArrowHeight = getDimen(R.dimen.navigation_edge_entry_arrow_height)
+ activeArrowLength = getDimen(R.dimen.navigation_edge_active_arrow_length)
+ activeArrowHeight = getDimen(R.dimen.navigation_edge_active_arrow_height)
+ stretchedArrowLength = getDimen(R.dimen.navigation_edge_stretched_arrow_length)
+ stretchedArrowHeight = getDimen(R.dimen.navigation_edge_stretched_arrow_height)
+ cancelledArrowLength = getDimen(R.dimen.navigation_edge_cancelled_arrow_length)
+ cancelledArrowHeight = getDimen(R.dimen.navigation_edge_cancelled_arrow_height)
+ entryMargin = getDimen(R.dimen.navigation_edge_entry_margin)
+ entryBackgroundWidth = getDimen(R.dimen.navigation_edge_entry_background_width)
+ entryBackgroundHeight = getDimen(R.dimen.navigation_edge_entry_background_height)
+ entryEdgeCorners = getDimen(R.dimen.navigation_edge_entry_edge_corners)
+ entryFarCorners = getDimen(R.dimen.navigation_edge_entry_far_corners)
+ preThresholdMargin = getDimen(R.dimen.navigation_edge_pre_threshold_margin)
+ preThresholdBackgroundWidth =
+ getDimen(R.dimen.navigation_edge_pre_threshold_background_width)
+ preThresholdBackgroundHeight =
+ getDimen(R.dimen.navigation_edge_pre_threshold_background_height)
+ preThresholdEdgeCorners = getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners)
+ preThresholdFarCorners = getDimen(R.dimen.navigation_edge_pre_threshold_far_corners)
+ activeMargin = getDimen(R.dimen.navigation_edge_active_margin)
+ activeBackgroundWidth = getDimen(R.dimen.navigation_edge_active_background_width)
+ activeBackgroundHeight = getDimen(R.dimen.navigation_edge_active_background_height)
+ activeEdgeCorners = getDimen(R.dimen.navigation_edge_active_edge_corners)
+ activeFarCorners = getDimen(R.dimen.navigation_edge_active_far_corners)
+ fullyStretchedThreshold = getDimen(R.dimen.navigation_edge_stretch_threshold)
+ stretchMargin = getDimen(R.dimen.navigation_edge_stretch_margin)
+ stretchBackgroundWidth = getDimen(R.dimen.navigation_edge_stretch_background_width)
+ stretchBackgroundHeight = getDimen(R.dimen.navigation_edge_stretch_background_height)
+ stretchEdgeCorners = getDimen(R.dimen.navigation_edge_stretch_left_corners)
+ stretchFarCorners = getDimen(R.dimen.navigation_edge_stretch_right_corners)
+ arrowPaddingEnd = getPx(R.dimen.navigation_edge_panel_padding)
+ minArrowYPosition = getPx(R.dimen.navigation_edge_arrow_min_y)
+ fingerOffset = getPx(R.dimen.navigation_edge_finger_offset)
+ swipeTriggerThreshold = getDimen(R.dimen.navigation_edge_action_drag_threshold)
+ swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold)
+ minDeltaForSwitch = getPx(R.dimen.navigation_edge_minimum_x_delta_for_switch)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index 5510eb172cd7..09c4cb760c90 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -57,7 +57,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import javax.inject.Inject;
@@ -126,7 +125,7 @@ public class TvOngoingPrivacyChip extends CoreStartable implements PrivacyItemCo
private final Runnable mCollapseRunnable = this::collapseChip;
private final Runnable mAccessibilityRunnable = this::makeAccessibilityAnnouncement;
- private final List<PrivacyItem> mItemsBeforeLastAnnouncement = new LinkedList<>();
+ private final List<PrivacyItem> mItemsBeforeLastAnnouncement = new ArrayList<>();
@State
private int mState = STATE_NOT_SHOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d03a2e55d628..24168089f77a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -57,7 +57,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.LifecycleFragment;
-import com.android.systemui.util.Utils;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -624,7 +623,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}
- updateMediaPositions();
+ mQqsMediaHost.setSquishFraction(mSquishinessFraction);
}
private void setAlphaAnimationProgress(float progress) {
@@ -644,10 +643,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mLastQSExpansion == 1.0f) {
// Fully expanded, let's set the layout bounds as clip bounds. This is necessary because
// it's a scrollview and otherwise wouldn't be clipped. However, we set the horizontal
- // bounds so the pages go to the ends of QSContainerImpl
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mQSPanelScrollView.getLayoutParams();
- mQsBounds.set(-lp.leftMargin, 0, mQSPanelScrollView.getWidth() + lp.rightMargin,
+ // bounds so the pages go to the ends of QSContainerImpl (most cases) or its parent
+ // (large screen portrait)
+ int sideMargin = getResources().getDimensionPixelSize(
+ R.dimen.qs_tiles_page_horizontal_margin) * 2;
+ mQsBounds.set(-sideMargin, 0, mQSPanelScrollView.getWidth() + sideMargin,
mQSPanelScrollView.getHeight());
}
mQSPanelScrollView.setClipBounds(mQsBounds);
@@ -660,54 +660,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
- mQSPanelScrollView.getPaddingBottom());
}
- private void updateMediaPositions() {
- if (Utils.useQsMediaPlayer(getContext())) {
- mContainer.getLocationOnScreen(mTmpLocation);
- float absoluteBottomPosition = mTmpLocation[1] + mContainer.getHeight();
- // The Media can be scrolled off screen by default, let's offset it
- float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
- + mQSPanelScrollView.getScrollRange();
- pinToBottom(expandedMediaPosition, mQsMediaHost, true /* expanded */);
- // The expanded media host should never move above the laid out position
- pinToBottom(absoluteBottomPosition, mQqsMediaHost, false /* expanded */);
- }
- }
-
- private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) {
- View hostView = mediaHost.getHostView();
- // On keyguard we cross-fade to expanded, so no need to pin it.
- // If the collapsed qs isn't visible, we also just keep it at the laid out position.
- if (mLastQSExpansion > 0 && !isKeyguardState() && mQqsMediaHost.getVisible()) {
- float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView)
- - hostView.getHeight();
- float currentPosition = mediaHost.getCurrentBounds().top
- - hostView.getTranslationY();
- float translationY = targetPosition - currentPosition;
- if (expanded) {
- // Never go below the laid out position. This is necessary since the qs panel can
- // change in height and we don't want to ever go below it's position
- translationY = Math.min(translationY, 0);
- } else {
- translationY = Math.max(translationY, 0);
- }
- hostView.setTranslationY(translationY);
- } else {
- hostView.setTranslationY(0);
- }
- }
-
- private float getTotalBottomMargin(View startView) {
- int result = 0;
- View child = startView;
- View parent = (View) startView.getParent();
- while (!(parent instanceof QSContainerImpl) && parent != null) {
- result += parent.getHeight() - child.getBottom();
- child = parent;
- parent = (View) parent.getParent();
- }
- return result;
- }
-
private boolean headerWillBeAnimating() {
return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
&& !isKeyguardState();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 1488231275c3..a92c7e3c8554 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -39,6 +39,7 @@ import com.android.systemui.qs.tiles.ColorInversionTile;
import com.android.systemui.qs.tiles.DataSaverTile;
import com.android.systemui.qs.tiles.DeviceControlsTile;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.qs.tiles.DreamTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.InternetTile;
@@ -96,6 +97,7 @@ public class QSFactoryImpl implements QSFactory {
private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider;
private final Provider<OneHandedModeTile> mOneHandedModeTileProvider;
+ private final Provider<DreamTile> mDreamTileProvider;
private final Lazy<QSHost> mQsHostLazy;
private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -132,7 +134,8 @@ public class QSFactoryImpl implements QSFactory {
Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
Provider<OneHandedModeTile> oneHandedModeTileProvider,
- Provider<ColorCorrectionTile> colorCorrectionTileProvider) {
+ Provider<ColorCorrectionTile> colorCorrectionTileProvider,
+ Provider<DreamTile> dreamTileProvider) {
mQsHostLazy = qsHostLazy;
mCustomTileBuilderProvider = customTileBuilderProvider;
@@ -165,6 +168,7 @@ public class QSFactoryImpl implements QSFactory {
mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
mOneHandedModeTileProvider = oneHandedModeTileProvider;
mColorCorrectionTileProvider = colorCorrectionTileProvider;
+ mDreamTileProvider = dreamTileProvider;
}
/** Creates a tile with a type based on {@code tileSpec} */
@@ -238,6 +242,8 @@ public class QSFactoryImpl implements QSFactory {
return mOneHandedModeTileProvider.get();
case "color_correction":
return mColorCorrectionTileProvider.get();
+ case "dream":
+ return mDreamTileProvider.get();
}
// Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 59164dea9c45..5147d5934039 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -670,7 +670,8 @@ internal object SubtitleArrayMapping {
"qr_code_scanner" to R.array.tile_states_qr_code_scanner,
"alarm" to R.array.tile_states_alarm,
"onehanded" to R.array.tile_states_onehanded,
- "color_correction" to R.array.tile_states_color_correction
+ "color_correction" to R.array.tile_states_color_correction,
+ "dream" to R.array.tile_states_dream
)
fun getSubtitleId(spec: String?): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index f736231bc22b..da5202bc3645 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -19,9 +19,7 @@ package com.android.systemui.qs.tiles;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
@@ -134,9 +132,10 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth);
state.stateDescription = "";
+
if (enabled) {
if (connected) {
- state.icon = new BluetoothConnectedTileIcon();
+ state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_on);
if (!TextUtils.isEmpty(mController.getConnectedDeviceName())) {
state.label = mController.getConnectedDeviceName();
}
@@ -145,21 +144,19 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
+ ", " + state.secondaryLabel;
} else if (state.isTransient) {
state.icon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_bluetooth_transient_animation);
+ R.drawable.qs_bluetooth_icon_search);
state.stateDescription = state.secondaryLabel;
} else {
state.icon =
- ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
+ ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
state.stateDescription = mContext.getString(R.string.accessibility_not_connected);
}
state.state = Tile.STATE_ACTIVE;
} else {
- state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
+ state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
state.state = Tile.STATE_INACTIVE;
}
- state.dualLabelContentDescription = mContext.getResources().getString(
- R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
}
@@ -244,22 +241,4 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
refreshState();
}
};
-
- /**
- * Bluetooth icon wrapper (when connected with no battery indicator) for Quick Settings. This is
- * used instead of {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to
- * use a context that reflects dark/light theme attributes.
- */
- private class BluetoothConnectedTileIcon extends Icon {
-
- BluetoothConnectedTileIcon() {
- // Do nothing. Default constructor to limit visibility.
- }
-
- @Override
- public Drawable getDrawable(Context context) {
- // This method returns Pair<Drawable, String> - the first value is the drawable.
- return context.getDrawable(R.drawable.ic_bluetooth_connected);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
new file mode 100644
index 000000000000..22e725b41a64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2022 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.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.service.quicksettings.Tile;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.dagger.DreamModule;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/** Quick settings tile: Screensaver (dream) **/
+public class DreamTile extends QSTileImpl<QSTile.BooleanState> {
+
+ private static final String LOG_TAG = "QSDream";
+ private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_screen_saver);
+ private final IDreamManager mDreamManager;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final SettingObserver mEnabledSettingObserver;
+ private final SettingObserver mDreamSettingObserver;
+ private final UserTracker mUserTracker;
+ private final boolean mDreamSupported;
+ private final boolean mDreamOnlyEnabledForSystemUser;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ refreshState();
+ }
+ };
+
+ @Inject
+ public DreamTile(
+ QSHost host,
+ @Background Looper backgroundLooper,
+ @Main Handler mainHandler,
+ FalsingManager falsingManager,
+ MetricsLogger metricsLogger,
+ StatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter,
+ QSLogger qsLogger,
+ IDreamManager dreamManager,
+ SecureSettings secureSettings,
+ BroadcastDispatcher broadcastDispatcher,
+ UserTracker userTracker,
+ @Named(DreamModule.DREAM_SUPPORTED) boolean dreamSupported,
+ @Named(DreamModule.DREAM_ONLY_ENABLED_FOR_SYSTEM_USER)
+ boolean dreamOnlyEnabledForSystemUser
+ ) {
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
+ mDreamManager = dreamManager;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mEnabledSettingObserver = new SettingObserver(secureSettings, mHandler,
+ Settings.Secure.SCREENSAVER_ENABLED) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ refreshState();
+ }
+ };
+ mDreamSettingObserver = new SettingObserver(secureSettings, mHandler,
+ Settings.Secure.SCREENSAVER_COMPONENTS) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ refreshState();
+ }
+ };
+ mUserTracker = userTracker;
+ mDreamSupported = dreamSupported;
+ mDreamOnlyEnabledForSystemUser = dreamOnlyEnabledForSystemUser;
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ super.handleSetListening(listening);
+
+ if (listening) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ mBroadcastDispatcher.registerReceiver(mReceiver, filter);
+ } else {
+ mBroadcastDispatcher.unregisterReceiver(mReceiver);
+ }
+ mEnabledSettingObserver.setListening(listening);
+ mDreamSettingObserver.setListening(listening);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ protected void handleClick(@Nullable View view) {
+ try {
+ if (mDreamManager.isDreaming()) {
+ mDreamManager.awaken();
+ } else {
+ mDreamManager.dream();
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can't dream", e);
+ }
+ }
+
+ @Override
+ protected void handleLongClick(@Nullable View view) {
+ try {
+ // Need to wake on long click so bouncer->settings works.
+ mDreamManager.awaken();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can't awaken", e);
+ }
+ super.handleLongClick(view);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ state.label = getTileLabel();
+ state.secondaryLabel = getActiveDreamName();
+ state.contentDescription = getContentDescription(state.secondaryLabel);
+ state.icon = mIcon;
+
+ if (getActiveDream() == null || !isScreensaverEnabled()) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ } else {
+ state.state = isDreaming() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ }
+ }
+
+ @Nullable
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_DREAM_SETTINGS);
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_screensaver_label);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ // Only enable for devices that have dreams for the user(s) that can dream.
+ // For now, restrict to debug users.
+ return Build.isDebuggable()
+ && mDreamSupported
+ && (!mDreamOnlyEnabledForSystemUser || mUserTracker.getUserHandle().isSystem());
+ }
+
+ @VisibleForTesting
+ protected CharSequence getContentDescription(CharSequence dreamName) {
+ return !TextUtils.isEmpty(dreamName)
+ ? getTileLabel() + ", " + dreamName : getTileLabel();
+ }
+
+ private boolean isDreaming() {
+ try {
+ return mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can't check if dreaming", e);
+ return false;
+ }
+ }
+
+ private ComponentName getActiveDream() {
+ try {
+ final ComponentName[] dreams = mDreamManager.getDreamComponents();
+ return dreams != null && dreams.length > 0 ? dreams[0] : null;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get active dream", e);
+ return null;
+ }
+ }
+
+ private CharSequence getActiveDreamName() {
+ final ComponentName componentName = getActiveDream();
+ if (componentName != null) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ ServiceInfo ri = pm.getServiceInfo(componentName, 0);
+ if (ri != null) {
+ return ri.loadLabel(pm);
+ }
+ } catch (PackageManager.NameNotFoundException exc) {
+ return null; // uninstalled?
+ }
+ }
+ return null;
+ }
+
+ private boolean isScreensaverEnabled() {
+ return mEnabledSettingObserver.getValue() == 1;
+ }
+}
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 e040ad08513f..170fecf1c8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -68,12 +68,16 @@ import javax.inject.Inject;
/** Quick settings tile: Internet **/
public class InternetTile extends QSTileImpl<SignalState> {
private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+ private static final int LAST_STATE_UNKNOWN = -1;
+ private static final int LAST_STATE_CELLULAR = 0;
+ private static final int LAST_STATE_WIFI = 1;
+ private static final int LAST_STATE_ETHERNET = 2;
protected final NetworkController mController;
private final AccessPointController mAccessPointController;
private final DataUsageController mDataController;
// The last updated tile state, 0: mobile, 1: wifi, 2: ethernet.
- private int mLastTileState = -1;
+ private int mLastTileState = LAST_STATE_UNKNOWN;
protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
private final InternetDialogFactory mInternetDialogFactory;
@@ -365,7 +369,11 @@ public class InternetTile extends QSTileImpl<SignalState> {
mWifiInfo.mNoDefaultNetwork = noDefaultNetwork;
mWifiInfo.mNoValidatedNetwork = noValidatedNetwork;
mWifiInfo.mNoNetworksAvailable = noNetworksAvailable;
- refreshState(mWifiInfo);
+ if (mLastTileState == LAST_STATE_WIFI) {
+ refreshState(mWifiInfo);
+ } else {
+ refreshState(mCellularInfo);
+ }
}
@Override
@@ -381,23 +389,23 @@ public class InternetTile extends QSTileImpl<SignalState> {
@Override
protected void handleUpdateState(SignalState state, Object arg) {
if (arg instanceof CellularCallbackInfo) {
- mLastTileState = 0;
+ mLastTileState = LAST_STATE_CELLULAR;
handleUpdateCellularState(state, arg);
} else if (arg instanceof WifiCallbackInfo) {
- mLastTileState = 1;
+ mLastTileState = LAST_STATE_WIFI;
handleUpdateWifiState(state, arg);
} else if (arg instanceof EthernetCallbackInfo) {
- mLastTileState = 2;
+ mLastTileState = LAST_STATE_ETHERNET;
handleUpdateEthernetState(state, arg);
} else {
// handleUpdateState will be triggered when user expands the QuickSetting panel with
// arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo
// should be used to refresh the tile.
- if (mLastTileState == 0) {
+ if (mLastTileState == LAST_STATE_CELLULAR) {
handleUpdateCellularState(state, mSignalCallback.mCellularInfo);
- } else if (mLastTileState == 1) {
+ } else if (mLastTileState == LAST_STATE_WIFI) {
handleUpdateWifiState(state, mSignalCallback.mWifiInfo);
- } else if (mLastTileState == 2) {
+ } else if (mLastTileState == LAST_STATE_ETHERNET) {
handleUpdateEthernetState(state, mSignalCallback.mEthernetInfo);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 177c82ed3d78..600874f0d01a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -57,6 +57,7 @@ import javax.inject.Inject;
/** Quick settings tile: Rotation **/
public class RotationLockTile extends QSTileImpl<BooleanState> implements
BatteryController.BatteryStateChangeCallback {
+ private static final String EMPTY_SECONDARY_STRING = "";
private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
private final RotationLockController mController;
@@ -144,13 +145,15 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements
&& mController.isCameraRotationEnabled();
state.value = !rotationLocked;
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- state.icon = mIcon;
+ state.icon = ResourceIcon.get(R.drawable.qs_auto_rotate_icon_off);
state.contentDescription = getAccessibilityString(rotationLocked);
- if (!rotationLocked && cameraRotation) {
- state.secondaryLabel = mContext.getResources().getString(
- R.string.rotation_lock_camera_rotation_on);
+ if (!rotationLocked) {
+ state.secondaryLabel = cameraRotation ? mContext.getResources().getString(
+ R.string.rotation_lock_camera_rotation_on)
+ : EMPTY_SECONDARY_STRING;
+ state.icon = ResourceIcon.get(R.drawable.qs_auto_rotate_icon_on);
} else {
- state.secondaryLabel = "";
+ state.secondaryLabel = EMPTY_SECONDARY_STRING;
}
state.stateDescription = state.secondaryLabel;
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 6eb54f799a24..19cef526ca2c 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
@@ -338,12 +338,7 @@ public class InternetDialog extends SystemUIDialog implements
private void setOnClickListener() {
mMobileNetworkLayout.setOnClickListener(v -> {
- if (mInternetDialogController.isMobileDataEnabled()
- && !mInternetDialogController.isDeviceLocked()) {
- if (!mInternetDialogController.activeNetworkIsCellular()) {
- mInternetDialogController.connectCarrierNetwork();
- }
- }
+ mInternetDialogController.connectCarrierNetwork();
});
mMobileDataToggle.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
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 f1fdae7db482..f629a0361ddb 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
@@ -675,12 +675,40 @@ public class InternetDialogController implements AccessPointController.AccessPoi
}
void connectCarrierNetwork() {
- final MergedCarrierEntry mergedCarrierEntry =
+ String errorLogPrefix = "Fail to connect carrier network : ";
+
+ if (!isMobileDataEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, errorLogPrefix + "settings OFF");
+ }
+ return;
+ }
+ if (isDeviceLocked()) {
+ if (DEBUG) {
+ Log.d(TAG, errorLogPrefix + "device locked");
+ }
+ return;
+ }
+ if (activeNetworkIsCellular()) {
+ Log.d(TAG, errorLogPrefix + "already active");
+ return;
+ }
+
+ MergedCarrierEntry mergedCarrierEntry =
mAccessPointController.getMergedCarrierEntry();
- if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) {
- mergedCarrierEntry.connect(null /* ConnectCallback */, false);
- makeOverlayToast(R.string.wifi_wont_autoconnect_for_now);
+ if (mergedCarrierEntry == null) {
+ Log.e(TAG, errorLogPrefix + "no merged entry");
+ return;
}
+
+ if (!mergedCarrierEntry.canConnect()) {
+ Log.w(TAG, errorLogPrefix + "merged entry connect state "
+ + mergedCarrierEntry.getConnectedState());
+ return;
+ }
+
+ mergedCarrierEntry.connect(null /* ConnectCallback */, false);
+ makeOverlayToast(R.string.wifi_wont_autoconnect_for_now);
}
boolean isCarrierNetworkActive() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 9768e706764f..da943d2ea594 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -736,7 +736,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
- boolean bouncerShowing, boolean isDozing) {
+ boolean bouncerShowing, boolean isDozing, boolean panelExpanded) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
keyguardShowing && !keyguardOccluded)
.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 80d5f1681a79..3f1ca078753b 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -30,9 +30,9 @@ import androidx.annotation.GuardedBy
import androidx.annotation.WorkerThread
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE
import com.android.systemui.util.Assert
import java.io.PrintWriter
-import java.lang.IllegalStateException
import java.lang.ref.WeakReference
import java.util.concurrent.Executor
import kotlin.properties.ReadWriteProperty
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 6cfbb43fa25a..1ffa6f41d8a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -19,13 +19,12 @@ package com.android.systemui.statusbar;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
-import android.os.Looper;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
@@ -43,8 +42,9 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
protected final ArrayMap<String, AlertEntry> mAlertEntries = new ArrayMap<>();
protected final HeadsUpManagerLogger mLogger;
- public AlertingNotificationManager(HeadsUpManagerLogger logger) {
+ public AlertingNotificationManager(HeadsUpManagerLogger logger, @Main Handler handler) {
mLogger = logger;
+ mHandler = handler;
}
/**
@@ -57,8 +57,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
protected int mMinimumDisplayTime;
protected int mAutoDismissNotificationDecay;
- @VisibleForTesting
- public Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Handler mHandler;
/**
* Called when posting a new notification that should alert the user and appear on screen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index aa80b730d24f..6fd92024c18c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -23,8 +23,6 @@ import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.systemui.statusbar.phone.CentralSurfacesImpl.ONLY_CORE_APPS;
-
import android.annotation.Nullable;
import android.app.ITransientNotificationCallback;
import android.app.StatusBarManager;
@@ -514,8 +512,7 @@ public class CommandQueue extends IStatusBar.Stub implements
final int disabled1 = getDisabled1(DEFAULT_DISPLAY);
final int disabled2 = getDisabled2(DEFAULT_DISPLAY);
return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0
- && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
- && !ONLY_CORE_APPS;
+ && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 6602f9947051..0c89340ec396 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -49,12 +49,14 @@ import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Log;
@@ -92,6 +94,8 @@ import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
import java.text.NumberFormat;
+import java.util.HashSet;
+import java.util.Set;
import javax.inject.Inject;
@@ -112,12 +116,12 @@ public class KeyguardIndicationController {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
+ private static final boolean DEBUG = Build.IS_DEBUGGABLE;
private static final int MSG_HIDE_TRANSIENT = 1;
private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
- private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
private final Context mContext;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -166,6 +170,7 @@ public class KeyguardIndicationController {
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
private String mMessageToShowOnScreenOn;
+ private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
private boolean mInited;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -234,6 +239,22 @@ public class KeyguardIndicationController {
mScreenLifecycle = screenLifecycle;
mScreenLifecycle.addObserver(mScreenObserver);
+ mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+ final String msgsToShowOverride = Settings.Global.getString(mContext.getContentResolver(),
+ "coex_face_help_msgs"); // TODO: remove after UX testing b/231733975
+ if (msgsToShowOverride != null) {
+ final String[] msgIds = msgsToShowOverride.split("\\|");
+ for (String msgId : msgIds) {
+ mCoExFaceHelpMsgIdsToShow.add(Integer.parseInt(msgId));
+ }
+ } else {
+ int[] msgIds = context.getResources().getIntArray(
+ com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
+ for (int msgId : msgIds) {
+ mCoExFaceHelpMsgIdsToShow.add(msgId);
+ }
+ }
+
mHandler = new Handler(mainLooper) {
@Override
public void handleMessage(Message msg) {
@@ -924,6 +945,7 @@ public class KeyguardIndicationController {
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
pw.println(" trustGrantedIndication: " + getTrustGrantedIndication());
+ pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
mRotateTextViewController.dump(pw, args);
}
@@ -982,9 +1004,20 @@ public class KeyguardIndicationController {
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
return;
}
+
boolean showActionToUnlock =
msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ if (biometricSourceType == BiometricSourceType.FACE
+ && !showActionToUnlock
+ && mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ KeyguardUpdateMonitor.getCurrentUser())
+ && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+ if (DEBUG) {
+ Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
+ + ", due to co-ex logic");
+ }
+ return;
+ } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
mInitialTextColorState);
} else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
@@ -1001,14 +1034,20 @@ public class KeyguardIndicationController {
if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
return;
}
+
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ // no message if fingerprint is also enrolled
+ if (DEBUG) {
+ Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
+ }
+ return;
+ }
+
// The face timeout message is not very actionable, let's ask the user to
// manually retry.
- if (!mStatusBarKeyguardViewManager.isBouncerShowing()
- && mKeyguardUpdateMonitor.isUdfpsEnrolled()
- && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
- showFaceFailedTryFingerprintMsg(msgId, errString);
- } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
+ if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
mStatusBarKeyguardViewManager.showBouncerMessage(
mContext.getResources().getString(R.string.keyguard_try_fingerprint),
mInitialTextColorState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 76f9db44af66..1ce05ec7e7ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -736,12 +736,10 @@ public class NotificationMediaManager implements Dumpable {
}
boolean cannotAnimateDoze = mStatusBarStateController.isDozing()
&& !ScrimState.AOD.getAnimateChange();
- boolean needsBypassFading = mKeyguardStateController.isBypassFadingAnimation();
if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
== BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- || cannotAnimateDoze) && !needsBypassFading)
+ || cannotAnimateDoze))
|| hideBecauseOccluded) {
-
// We are unlocking directly - no animation!
mBackdrop.setVisibility(View.GONE);
mBackdropBack.setImageDrawable(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index d71dec8ff396..5cdd01f0ee0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -68,6 +68,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.util.DumpUtilsKt;
+import com.android.systemui.util.ListenerSet;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -75,6 +76,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
import dagger.Lazy;
@@ -118,6 +120,8 @@ public class NotificationRemoteInputManager implements Dumpable {
protected Callback mCallback;
private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>();
+ private final ListenerSet<Consumer<NotificationEntry>> mActionPressListeners =
+ new ListenerSet<>();
private final InteractionHandler mInteractionHandler = new InteractionHandler() {
@@ -401,6 +405,14 @@ public class NotificationRemoteInputManager implements Dumpable {
}
}
+ public void addActionPressListener(Consumer<NotificationEntry> listener) {
+ mActionPressListeners.addIfAbsent(listener);
+ }
+
+ public void removeActionPressListener(Consumer<NotificationEntry> listener) {
+ mActionPressListeners.remove(listener);
+ }
+
/**
* Activates a given {@link RemoteInput}
*
@@ -634,6 +646,9 @@ public class NotificationRemoteInputManager implements Dumpable {
if (mRemoteInputListener != null) {
mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry);
}
+ for (Consumer<NotificationEntry> listener : mActionPressListeners) {
+ listener.accept(entry);
+ }
}
/** Returns whether the notification should be lifetime extended for smart reply history */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
index f960eb7b6e9b..ed32008526d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
@@ -47,8 +47,6 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
void addEmergencyListener(EmergencyListener listener);
/** */
void removeEmergencyListener(EmergencyListener listener);
- /** */
- boolean hasEmergencyCryptKeeperText();
/** */
boolean isRadioOn();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index d49e1e6acc23..14ba64b61a85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -80,7 +80,6 @@ import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverControllerImpl;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.CarrierConfigTracker;
@@ -1448,11 +1447,6 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
/** */
- public boolean hasEmergencyCryptKeeperText() {
- return EncryptionHelper.IS_DATA_ENCRYPTED;
- }
-
- /** */
public boolean isRadioOn() {
return !mAirplaneMode;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index df412ed93f55..8cb18a06057e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -260,7 +260,7 @@ public class InstantAppNotifier extends CoreStartable
Intent browserIntent = getTaskIntent(taskId, userId);
Notification.Builder builder =
- new Notification.Builder(mContext, NotificationChannels.GENERAL);
+ new Notification.Builder(mContext, NotificationChannels.INSTANT);
if (browserIntent != null && browserIntent.isWebIntent()) {
// Make sure that this doesn't resolve back to an instant app
browserIntent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 6be8a491eead..e98ae8db4122 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -121,6 +121,12 @@ public class ListDumper {
sb.append(" (parent=")
.append(entry.getParent() != null ? entry.getParent().getKey() : null)
.append(")");
+
+ NotificationEntry notifEntry = entry.getRepresentativeEntry();
+ if (notifEntry != null) {
+ sb.append(" rank=")
+ .append(notifEntry.getRanking().getRank());
+ }
}
if (entry.getSection() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 6085096ee124..410593ac5493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -609,12 +609,21 @@ public class NotifCollection implements Dumpable {
}
checkForReentrantCall();
+ NotificationEntry collectionEntry = getEntry(entry.getKey());
+ String logKey = logKey(entry);
+ String collectionEntryIs = collectionEntry == null ? "null"
+ : entry == collectionEntry ? "same" : "different";
+
+ if (entry != collectionEntry) {
+ // TODO: We should probably make this throw, but that's too risky right now
+ mLogger.logEntryBeingExtendedNotInCollection(entry, extender, collectionEntryIs);
+ }
+
if (!entry.mLifetimeExtenders.remove(extender)) {
throw mEulogizer.record(new IllegalStateException(
- String.format(
- "Cannot end lifetime extension for extender \"%s\" (%s)",
- extender.getName(),
- extender)));
+ String.format("Cannot end lifetime extension for extender \"%s\""
+ + " of entry %s (collection entry is %s)",
+ extender.getName(), logKey, collectionEntryIs)));
}
mLogger.logLifetimeExtensionEnded(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index 4daed77c0954..6a3799b38dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -79,6 +79,11 @@ public class NotifInflaterImpl implements NotifInflater {
entry.abortTask();
}
+ @Override
+ public void releaseViews(@NonNull NotificationEntry entry) {
+ requireBinder().releaseViews(entry);
+ }
+
private NotificationContentInflater.InflationCallback wrapInflationCallback(
InflationCallback callback) {
return new NotificationContentInflater.InflationCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index df2fe4e8511f..2a8a67281c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -990,7 +990,7 @@ public class ShadeListBuilder implements Dumpable {
// Check for suppressed order changes
if (!getStabilityManager().isEveryChangeAllowed()) {
mForceReorderable = true;
- boolean isSorted = isSorted(mNotifList, mTopLevelComparator);
+ boolean isSorted = isShadeSorted();
mForceReorderable = false;
if (!isSorted) {
getStabilityManager().onEntryReorderSuppressed();
@@ -999,9 +999,23 @@ public class ShadeListBuilder implements Dumpable {
Trace.endSection();
}
+ private boolean isShadeSorted() {
+ if (!isSorted(mNotifList, mTopLevelComparator)) {
+ return false;
+ }
+ for (ListEntry entry : mNotifList) {
+ if (entry instanceof GroupEntry) {
+ if (!isSorted(((GroupEntry) entry).getChildren(), mGroupChildrenComparator)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
/** Determine whether the items in the list are sorted according to the comparator */
@VisibleForTesting
- public static <T> boolean isSorted(List<T> items, Comparator<T> comparator) {
+ public static <T> boolean isSorted(List<T> items, Comparator<? super T> comparator) {
if (items.size() <= 1) {
return true;
}
@@ -1209,7 +1223,7 @@ public class ShadeListBuilder implements Dumpable {
};
- private final Comparator<ListEntry> mGroupChildrenComparator = (o1, o2) -> {
+ private final Comparator<NotificationEntry> mGroupChildrenComparator = (o1, o2) -> {
int index1 = canReorder(o1) ? -1 : o1.getPreviousAttachState().getStableIndex();
int index2 = canReorder(o2) ? -1 : o2.getPreviousAttachState().getStableIndex();
int cmp = Integer.compare(index1, index2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index da0169bd6dc4..a61db4107c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
import android.app.Notification.GROUP_ALERT_SUMMARY
import android.util.ArrayMap
-import android.util.ArraySet
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -41,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
+import java.util.function.Consumer
import javax.inject.Inject
/**
@@ -85,6 +85,7 @@ class HeadsUpCoordinator @Inject constructor(
pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilter)
pipeline.addPromoter(mNotifPromoter)
pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
+ mRemoteInputManager.addActionPressListener(mActionPressListener)
}
private fun onHeadsUpViewBound(entry: NotificationEntry) {
@@ -448,6 +449,14 @@ class HeadsUpCoordinator @Inject constructor(
(entry.sbn.notification.flags and Notification.FLAG_ONLY_ALERT_ONCE) == 0)
}
+ /** When an action is pressed on a notification, end HeadsUp lifetime extension. */
+ private val mActionPressListener = Consumer<NotificationEntry> { entry ->
+ if (mNotifsExtendingLifetime.contains(entry)) {
+ val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key)
+ mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis)
+ }
+ }
+
private val mLifetimeExtender = object : NotifLifetimeExtender {
override fun getName() = TAG
@@ -503,6 +512,7 @@ class HeadsUpCoordinator @Inject constructor(
private val mOnHeadsUpChangedListener = object : OnHeadsUpChangedListener {
override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
if (!isHeadsUp) {
+ mNotifPromoter.invalidateList()
mHeadsUpViewBinder.unbindHeadsUpView(entry)
endNotifLifetimeExtensionIfExtended(entry)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index aac5b8d6b2eb..4895fa3fcb56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -19,12 +19,12 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 35fe0ee7cdb1..457e8c9f6066 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -375,6 +375,7 @@ public class PreparationCoordinator implements Coordinator {
private void freeNotifViews(NotificationEntry entry) {
mViewBarn.removeViewForEntry(entry);
+ mNotifInflater.releaseViews(entry);
// TODO: clear the entry's row here, or even better, stop setting the row on the entry!
mInflationStates.put(entry, STATE_UNINFLATED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 57fd1975e13a..5ac481341d43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.SectionClassifier;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -28,6 +27,7 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
@@ -51,7 +51,7 @@ public class RankingCoordinator implements Coordinator {
public static final boolean SHOW_ALL_SECTIONS = false;
private final StatusBarStateController mStatusBarStateController;
private final HighPriorityProvider mHighPriorityProvider;
- private final SectionClassifier mSectionClassifier;
+ private final SectionStyleProvider mSectionStyleProvider;
private final NodeController mSilentNodeController;
private final SectionHeaderController mSilentHeaderController;
private final NodeController mAlertingHeaderController;
@@ -62,13 +62,13 @@ public class RankingCoordinator implements Coordinator {
public RankingCoordinator(
StatusBarStateController statusBarStateController,
HighPriorityProvider highPriorityProvider,
- SectionClassifier sectionClassifier,
+ SectionStyleProvider sectionStyleProvider,
@AlertingHeader NodeController alertingHeaderController,
@SilentHeader SectionHeaderController silentHeaderController,
@SilentHeader NodeController silentNodeController) {
mStatusBarStateController = statusBarStateController;
mHighPriorityProvider = highPriorityProvider;
- mSectionClassifier = sectionClassifier;
+ mSectionStyleProvider = sectionStyleProvider;
mAlertingHeaderController = alertingHeaderController;
mSilentNodeController = silentNodeController;
mSilentHeaderController = silentHeaderController;
@@ -77,7 +77,7 @@ public class RankingCoordinator implements Coordinator {
@Override
public void attach(NotifPipeline pipeline) {
mStatusBarStateController.addCallback(mStatusBarStateCallback);
- mSectionClassifier.setMinimizedSections(Collections.singleton(mMinimizedNotifSectioner));
+ mSectionStyleProvider.setMinimizedSections(Collections.singleton(mMinimizedNotifSectioner));
pipeline.addPreGroupFilter(mSuspendedFilter);
pipeline.addPreGroupFilter(mDndVisualEffectsFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
index 4e9d3ac07a96..9e8b35af1bce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
@@ -19,11 +19,11 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.content.Context
import com.android.systemui.R
import com.android.systemui.statusbar.notification.AssistantFeedbackController
-import com.android.systemui.statusbar.notification.SectionClassifier
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.statusbar.notification.collection.render.NotifRowController
import javax.inject.Inject
@@ -35,7 +35,7 @@ import javax.inject.Inject
class RowAppearanceCoordinator @Inject internal constructor(
context: Context,
private var mAssistantFeedbackController: AssistantFeedbackController,
- private var mSectionClassifier: SectionClassifier
+ private var mSectionStyleProvider: SectionStyleProvider
) : Coordinator {
private var entryToExpand: NotificationEntry? = null
@@ -55,7 +55,7 @@ class RowAppearanceCoordinator @Inject internal constructor(
private fun onBeforeRenderList(list: List<ListEntry>) {
entryToExpand = list.firstOrNull()?.representativeEntry?.takeIf { entry ->
- !mSectionClassifier.isMinimizedSection(entry.section!!)
+ !mSectionStyleProvider.isMinimizedSection(entry.section!!)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index d7bd95c0949e..b9d23b4a344a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -16,8 +16,9 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
+
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.phone.NotifPanelEvents;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.Compile;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.PrintWriter;
@@ -54,6 +56,8 @@ import javax.inject.Inject;
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator, Dumpable,
NotifPanelEvents.Listener {
+ public static final String TAG = "VisualStability";
+ public static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
private final DelayableExecutor mDelayableExecutor;
private final HeadsUpManager mHeadsUpManager;
private final NotifPanelEvents mNotifPanelEvents;
@@ -61,7 +65,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
private final VisualStabilityProvider mVisualStabilityProvider;
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private boolean mScreenOn;
+ private boolean mSleepy = true;
+ private boolean mFullyDozed;
private boolean mPanelExpanded;
private boolean mPulsing;
private boolean mNotifPanelCollapsing;
@@ -104,8 +109,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
@Override
public void attach(NotifPipeline pipeline) {
mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
- mScreenOn = mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
- || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
+ mSleepy = mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP;
+ mFullyDozed = mStatusBarStateController.getDozeAmount() == 1f;
mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
mPulsing = mStatusBarStateController.isPulsing();
@@ -113,6 +118,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
pipeline.setVisualStabilityManager(mNotifStabilityManager);
}
+
// TODO(b/203826051): Ensure stability manager can allow reordering off-screen
// HUNs to the top of the shade
private final NotifStabilityManager mNotifStabilityManager =
@@ -174,9 +180,18 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
}
};
- private void updateAllowedStates() {
+ private void updateAllowedStates(String field, boolean value) {
+ boolean wasPipelineRunAllowed = mPipelineRunAllowed;
+ boolean wasReorderingAllowed = mReorderingAllowed;
mPipelineRunAllowed = !isPanelCollapsingOrLaunchingActivity();
mReorderingAllowed = isReorderingAllowed();
+ if (DEBUG && (wasPipelineRunAllowed != mPipelineRunAllowed
+ || wasReorderingAllowed != mReorderingAllowed)) {
+ Log.d(TAG, "Stability allowances changed:"
+ + " pipelineRunAllowed " + wasPipelineRunAllowed + "->" + mPipelineRunAllowed
+ + " reorderingAllowed " + wasReorderingAllowed + "->" + mReorderingAllowed
+ + " when setting " + field + "=" + value);
+ }
if ((mPipelineRunAllowed && mIsSuppressingPipelineRun)
|| (mReorderingAllowed && (mIsSuppressingGroupChange
|| isSuppressingSectionChange()
@@ -195,7 +210,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
}
private boolean isReorderingAllowed() {
- return (!mScreenOn || !mPanelExpanded) && !mPulsing;
+ return ((mFullyDozed && mSleepy) || !mPanelExpanded) && !mPulsing;
}
/**
@@ -235,27 +250,37 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
@Override
public void onPulsingChanged(boolean pulsing) {
mPulsing = pulsing;
- updateAllowedStates();
+ updateAllowedStates("pulsing", pulsing);
}
@Override
public void onExpandedChanged(boolean expanded) {
mPanelExpanded = expanded;
- updateAllowedStates();
+ updateAllowedStates("panelExpanded", expanded);
+ }
+
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ final boolean fullyDozed = linear == 1f;
+ mFullyDozed = fullyDozed;
+ updateAllowedStates("fullyDozed", fullyDozed);
}
};
final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedGoingToSleep() {
- mScreenOn = false;
- updateAllowedStates();
+ // NOTE: this method is called much earlier than what we consider "finished" going to
+ // sleep (the animation isn't done), so we also need to check the doze amount is not 1
+ // and use the combo to determine that the locked shade is not visible.
+ mSleepy = true;
+ updateAllowedStates("sleepy", true);
}
@Override
public void onStartedWakingUp() {
- mScreenOn = true;
- updateAllowedStates();
+ mSleepy = false;
+ updateAllowedStates("sleepy", false);
}
};
@@ -265,7 +290,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
pw.println(" notifPanelCollapsing: " + mNotifPanelCollapsing);
pw.println(" launchingNotifActivity: " + mNotifPanelLaunchingActivity);
pw.println("reorderingAllowed: " + mReorderingAllowed);
- pw.println(" screenOn: " + mScreenOn);
+ pw.println(" sleepy: " + mSleepy);
+ pw.println(" fullyDozed: " + mFullyDozed);
pw.println(" panelExpanded: " + mPanelExpanded);
pw.println(" pulsing: " + mPulsing);
pw.println("isSuppressingPipelineRun: " + mIsSuppressingPipelineRun);
@@ -285,12 +311,12 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
@Override
public void onPanelCollapsingChanged(boolean isCollapsing) {
mNotifPanelCollapsing = isCollapsing;
- updateAllowedStates();
+ updateAllowedStates("notifPanelCollapsing", isCollapsing);
}
@Override
public void onLaunchingActivityChanged(boolean isLaunchingActivity) {
mNotifPanelLaunchingActivity = isLaunchingActivity;
- updateAllowedStates();
+ updateAllowedStates("notifPanelLaunchingActivity", isLaunchingActivity);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
index d98e7f76a11b..567ec85cf6c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
@@ -47,6 +47,11 @@ interface NotifInflater {
fun abortInflation(entry: NotificationEntry)
/**
+ * Called to let the system remove the content views from the notification row.
+ */
+ fun releaseViews(entry: NotificationEntry)
+
+ /**
* Callback once all the views are inflated and bound for a given NotificationEntry.
*/
interface InflationCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
index 497691d18844..2227be120309 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.notification.collection.inflation
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.SectionClassifier
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import javax.inject.Inject
/**
@@ -28,13 +28,13 @@ import javax.inject.Inject
*/
@SysUISingleton
open class NotifUiAdjustmentProvider @Inject constructor(
- private val sectionClassifier: SectionClassifier
+ private val sectionStyleProvider: SectionStyleProvider
) {
private fun isEntryMinimized(entry: NotificationEntry): Boolean {
val section = entry.section ?: error("Entry must have a section to determine if minimized")
val parent = entry.parent ?: error("Entry must have a parent to determine if minimized")
- val isMinimizedSection = sectionClassifier.isMinimizedSection(section)
+ val isMinimizedSection = sectionStyleProvider.isMinimizedSection(section)
val isTopLevelEntry = parent == GroupEntry.ROOT_ENTRY
val isGroupSummary = parent.summary == entry
return isMinimizedSection && (isTopLevelEntry || isGroupSummary)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index 3a4701c9ac76..46b467e8962d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -50,4 +50,9 @@ public interface NotificationRowBinder {
NotificationUiAdjustment oldAdjustment,
NotificationUiAdjustment newAdjustment,
NotificationRowContentBinder.InflationCallback callback);
+
+ /**
+ * Called when a notification is no longer likely to be displayed and can have its views freed.
+ */
+ void releaseViews(NotificationEntry entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4c7b2bbfb6d9..bf4ea1f2e86d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar.notification.collection.inflation;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
+
import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
@@ -159,6 +163,18 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
}
}
+ @Override
+ public void releaseViews(NotificationEntry entry) {
+ if (!entry.rowExists()) {
+ return;
+ }
+ final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
+ mRowContentBindStage.requestRebind(entry, null);
+ }
+
/**
* Bind row to various controllers and managers. This is only called when the row is first
* created.
@@ -247,6 +263,8 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
}
RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
+ params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+ params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index 263737e20a13..ea66f3b6dd42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -25,12 +25,9 @@ data class NotifSection(
val sectioner: NotifSectioner,
val index: Int
) {
- val label: String
- get() = "Section($index, $bucket, \"${sectioner.name}\")"
-
+ @PriorityBucket
+ val bucket: Int = sectioner.bucket
+ val label: String = "$index:$bucket:${sectioner.name}"
val headerController: NodeController? = sectioner.headerNodeController
-
val comparator: NotifComparator? = sectioner.comparator
-
- @PriorityBucket val bucket: Int = sectioner.bucket
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 7e7936717b84..ac0b1ee6c442 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -248,6 +248,20 @@ class NotifCollectionLogger @Inject constructor(
})
}
+ fun logEntryBeingExtendedNotInCollection(
+ entry: NotificationEntry,
+ extender: NotifLifetimeExtender,
+ collectionEntryIs: String
+ ) {
+ buffer.log(TAG, WARNING, {
+ str1 = entry.logKey
+ str2 = extender.name
+ str3 = collectionEntryIs
+ }, {
+ "While ending lifetime extension by $str2 of $str1, entry in collection is $str3"
+ })
+ }
+
fun logFutureDismissalReused(dismissal: FutureDismissal) {
buffer.log(TAG, INFO, {
str1 = dismissal.label
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt
index 68bdd18c9881..2148d3bb336a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification
+package com.android.systemui.statusbar.notification.collection.provider
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
@@ -34,7 +34,7 @@ import javax.inject.Inject
class SectionHeaderVisibilityProvider @Inject constructor(
context: Context
) {
- var neverShowSectionHeaders = context.resources.getBoolean(R.bool.config_notification_never_show_section_headers)
- private set
+ val neverShowSectionHeaders =
+ context.resources.getBoolean(R.bool.config_notification_never_show_section_headers)
var sectionHeadersVisible = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionClassifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt
index 1f2d0fe6c46e..50e7d1ce4ba0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionClassifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification
+package com.android.systemui.statusbar.notification.collection.provider
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
@@ -26,7 +26,7 @@ import javax.inject.Inject
* NOTE: This class exists to avoid putting metadata like "isMinimized" on the NotifSection
*/
@SysUISingleton
-class SectionClassifier @Inject constructor() {
+class SectionStyleProvider @Inject constructor() {
private lateinit var lowPrioritySections: Set<NotifSectioner>
/**
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
index 8be710c8842c..34d25cf9c3be 100644
--- 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
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.notification.collection.render
-import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
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
+import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
import com.android.systemui.util.Compile
import com.android.systemui.util.traceSection
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 6ed81078c3a4..51dc72848d9e 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
@@ -19,10 +19,10 @@ package com.android.systemui.statusbar.notification.collection.render
import android.content.Context
import android.view.View
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
-import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
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.provider.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.util.traceSection
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index e210f193b0a1..a063dbd99626 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -194,6 +194,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
+ if (!canAlertHeadsUpCommon(entry)) {
+ return false;
+ }
+
if (!canAlertAwakeCommon(entry)) {
return false;
}
@@ -267,6 +271,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
+ if (!canAlertHeadsUpCommon(entry)) {
+ mLogger.logNoPulsingNoAlert(sbn);
+ return false;
+ }
+
if (entry.shouldSuppressAmbient()) {
mLogger.logNoPulsingNoAmbientEffect(sbn);
return false;
@@ -294,12 +303,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
- // Don't alert notifications that are suppressed due to group alert behavior
- if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
- mLogger.logNoAlertingGroupAlertBehavior(sbn);
- return false;
- }
-
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressInterruptions(entry)) {
mLogger.logNoAlertingSuppressedBy(sbn, mSuppressors.get(i), /* awake */ false);
@@ -307,13 +310,31 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
}
}
- if (entry.hasJustLaunchedFullScreenIntent()) {
- mLogger.logNoAlertingRecentFullscreen(sbn);
+ if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
+ mLogger.keyguardHideNotification(entry.getKey());
return false;
}
- if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
- mLogger.keyguardHideNotification(entry.getKey());
+ return true;
+ }
+
+ /**
+ * Common checks for heads up notifications on regular and AOD displays.
+ *
+ * @param entry the entry to check
+ * @return true if these checks pass, false if the notification should not alert
+ */
+ private boolean canAlertHeadsUpCommon(NotificationEntry entry) {
+ StatusBarNotification sbn = entry.getSbn();
+
+ // Don't alert notifications that are suppressed due to group alert behavior
+ if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
+ mLogger.logNoAlertingGroupAlertBehavior(sbn);
+ return false;
+ }
+
+ if (entry.hasJustLaunchedFullScreenIntent()) {
+ mLogger.logNoAlertingRecentFullscreen(sbn);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 1cae60b3d37d..2bef4de295b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2075,6 +2075,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void applyLaunchAnimationParams(LaunchAnimationParameters params) {
if (params == null) {
+ // `null` params indicates the animation is over, which means we can't access
+ // params.getParentStartClipTopAmount() which has the value we want to restore.
+ // Fortunately, only NotificationShelf actually uses these values for anything other
+ // than this launch animation, so we can restore the value to 0 and it's right for now.
+ if (mNotificationParent != null) {
+ mNotificationParent.setClipTopAmount(0);
+ }
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index d71e76801b3b..e042e9cb2a19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -58,7 +58,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private static Rect mClipRect = new Rect();
private boolean mWillBeGone;
- private int mMinClipTopAmount = 0;
private boolean mClipToActualHeight = true;
private boolean mChangingPosition = false;
private ViewGroup mTransientContainer;
@@ -477,14 +476,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
mWillBeGone = willBeGone;
}
- public int getMinClipTopAmount() {
- return mMinClipTopAmount;
- }
-
- public void setMinClipTopAmount(int minClipTopAmount) {
- mMinClipTopAmount = minClipTopAmount;
- }
-
@Override
public void setLayerType(int layerType, Paint paint) {
// Allow resetting the layerType to NONE regardless of overlappingRendering
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index a552f999aeb4..a76f0827fc18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1312,6 +1312,7 @@ public class NotificationChildrenContainer extends ViewGroup
}
float bottomRoundness = last ? currentBottomRoundness : 0.0f;
child.setBottomRoundness(bottomRoundness, isShown() /* animate */);
+ child.setTopRoundness(0.0f, false /* animate */);
last = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ba57d57d0fd3..398ab0a9f32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1371,12 +1371,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
- final float shadeBottom = getHeight() - getEmptyBottomMargin();
final boolean skipHeightUpdate = shouldSkipHeightUpdate();
- if (!skipHeightUpdate) {
- final float expansionFraction = MathUtils.saturate(height / shadeBottom);
- mAmbientState.setExpansionFraction(expansionFraction);
- }
updateStackPosition();
if (!skipHeightUpdate) {
@@ -4531,31 +4526,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mClearAllInProgress = clearAllInProgress;
mAmbientState.setClearAllInProgress(clearAllInProgress);
mController.getNoticationRoundessManager().setClearAllInProgress(clearAllInProgress);
- handleClearAllClipping();
}
boolean getClearAllInProgress() {
return mClearAllInProgress;
}
- @ShadeViewRefactor(RefactorComponent.ADAPTER)
- private void handleClearAllClipping() {
- final int count = getChildCount();
- boolean previousChildWillBeDismissed = false;
- for (int i = 0; i < count; i++) {
- ExpandableView child = (ExpandableView) getChildAt(i);
- if (child.getVisibility() == GONE) {
- continue;
- }
- if (mClearAllInProgress && previousChildWillBeDismissed) {
- child.setMinClipTopAmount(child.getClipTopAmount());
- } else {
- child.setMinClipTopAmount(0);
- }
- previousChildWillBeDismissed = canChildBeCleared(child);
- }
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFooterViewNotGone() {
return mFooterView != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index e946bf1bb238..d5023ffd8b37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -91,7 +91,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
MODE_SHOW_BOUNCER,
MODE_ONLY_WAKE,
MODE_UNLOCK_COLLAPSING,
- MODE_UNLOCK_FADING,
MODE_DISMISS_BOUNCER,
MODE_WAKE_AND_UNLOCK_FROM_DREAM
})
@@ -138,15 +137,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 6;
/**
- * Faster mode of dismissing the lock screen when we cross fade to an app
- * (used for keyguard bypass.)
- */
- public static final int MODE_UNLOCK_FADING = 7;
-
- /**
* When bouncer is visible and will be dismissed.
*/
- public static final int MODE_DISMISS_BOUNCER = 8;
+ public static final int MODE_DISMISS_BOUNCER = 7;
/**
* How much faster we collapse the lockscreen when authenticating with biometric.
@@ -451,8 +444,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
}
switch (mMode) {
case MODE_DISMISS_BOUNCER:
- case MODE_UNLOCK_FADING:
- Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING");
+ Trace.beginSection("MODE_DISMISS_BOUNCER");
mKeyguardViewController.notifyKeyguardAuthenticated(
false /* strongAuth */);
Trace.endSection();
@@ -590,7 +582,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
boolean deviceDreaming = mUpdateMonitor.isDreaming();
boolean bypass = mKeyguardBypassController.getBypassEnabled()
- || mKeyguardBypassController.getUserHasDeviceEntryIntent();
+ || mAuthController.isUdfpsFingerDown();
if (!mUpdateMonitor.isDeviceInteractive()) {
if (!mKeyguardViewController.isShowing()) {
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
@@ -619,14 +611,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
if (mKeyguardViewController.isShowing()) {
if ((mKeyguardViewController.bouncerIsOrWillBeShowing()
|| mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) {
- if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
- return MODE_UNLOCK_FADING;
- } else {
- return MODE_DISMISS_BOUNCER;
- }
- } else if (unlockingAllowed) {
- return bypass || mAuthController.isUdfpsFingerDown()
- ? MODE_UNLOCK_FADING : MODE_NONE;
+ return MODE_DISMISS_BOUNCER;
+ } else if (unlockingAllowed && (bypass || mAuthController.isUdfpsFingerDown())) {
+ return MODE_UNLOCK_COLLAPSING;
} else {
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
}
@@ -802,7 +789,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
* on or off.
*/
public boolean isBiometricUnlock() {
- return isWakeAndUnlock() || mMode == MODE_UNLOCK_COLLAPSING || mMode == MODE_UNLOCK_FADING;
+ return isWakeAndUnlock() || mMode == MODE_UNLOCK_COLLAPSING;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 9c6ba3af5154..28356730dab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -396,8 +396,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
void keyguardGoingAway();
- void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration,
- boolean isBypassFading);
+ void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration);
void finishKeyguardFadingAway();
@@ -449,6 +448,8 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
void setBouncerShowing(boolean bouncerShowing);
+ void setBouncerShowingOverDream(boolean bouncerShowingOverDream);
+
void collapseShade();
int getWakefulnessState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 367684faa621..db1a70b59a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -63,7 +63,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
@@ -286,25 +285,10 @@ public class CentralSurfacesImpl extends CoreStartable implements
*/
private static final int HINT_RESET_DELAY_MS = 1200;
- private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
-
- /**
- * If true, the system is in the half-boot-to-decryption-screen state.
- * Prudently disable QS and notifications.
- */
- public static final boolean ONLY_CORE_APPS;
+ /** If true, the lockscreen will show a distinct wallpaper */
+ public static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
- static {
- boolean onlyCoreApps;
- try {
- IPackageManager packageManager =
- IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- onlyCoreApps = packageManager != null && packageManager.isOnlyCoreApps();
- } catch (RemoteException e) {
- onlyCoreApps = false;
- }
- ONLY_CORE_APPS = onlyCoreApps;
- }
+ private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final DreamOverlayStateController mDreamOverlayStateController;
@@ -442,6 +426,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
*/
protected int mState; // TODO: remove this. Just use StatusBarStateController
protected boolean mBouncerShowing;
+ private boolean mBouncerShowingOverDream;
private final PhoneStatusBarPolicy mIconPolicy;
@@ -1653,8 +1638,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
|| !mUserSwitcherController.isSimpleUserSwitcher())
&& !isShadeDisabled()
&& ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
- && !mDozing
- && !ONLY_CORE_APPS;
+ && !mDozing;
mNotificationPanelViewController.setQsExpansionEnabledPolicy(expandEnabled);
Log.d(TAG, "updateQsExpansionEnabled - QS Expand enabled: " + expandEnabled);
}
@@ -2516,6 +2500,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
animate, intent.getPackage(), (adapter) -> {
ActivityOptions options = new ActivityOptions(
CentralSurfaces.getActivityOptions(mDisplayId, adapter));
+
+ // We know that the intent of the caller is to dismiss the keyguard and
+ // this runnable is called right after the keyguard is solved, so we tell
+ // WM that we should dismiss it to avoid flickers when opening an activity
+ // that can also be shown over the keyguard.
+ options.setDismissKeyguard();
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (CameraIntents.isInsecureCameraIntent(intent)) {
@@ -3193,14 +3183,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
/**
* Notifies the status bar the Keyguard is fading away with the specified timings.
- * @param startTime the start time of the animations in uptime millis
+ * @param startTime the start time of the animations in uptime millis
* @param delay the precalculated animation delay in milliseconds
* @param fadeoutDuration the duration of the exit animation, in milliseconds
- * @param isBypassFading is this a fading away animation while bypassing
*/
@Override
- public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration,
- boolean isBypassFading) {
+ public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3208,7 +3196,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
mCommandQueue.appTransitionStarting(mDisplayId,
startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
- mKeyguardStateController.notifyKeyguardFadingAway(delay, fadeoutDuration, isBypassFading);
+ mKeyguardStateController.notifyKeyguardFadingAway(delay, fadeoutDuration);
}
/**
@@ -3329,9 +3317,13 @@ public class CentralSurfacesImpl extends CoreStartable implements
@Override
public boolean onBackPressed() {
- boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
- if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
- if (isScrimmedBouncer) {
+ final boolean isScrimmedBouncer =
+ mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
+ final boolean isBouncerOverDream = isBouncerShowingOverDream();
+
+ if (mStatusBarKeyguardViewManager.onBackPressed(
+ isScrimmedBouncer || isBouncerOverDream /* hideImmediately */)) {
+ if (isScrimmedBouncer || isBouncerOverDream) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
} else {
mNotificationPanelViewController.expandWithoutQs();
@@ -3353,7 +3345,8 @@ public class CentralSurfacesImpl extends CoreStartable implements
if (mNotificationPanelViewController.closeUserSwitcherIfOpen()) {
return true;
}
- if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
+ if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
+ && !isBouncerOverDream) {
if (mNotificationPanelViewController.canPanelBeCollapsed()) {
mShadeController.animateCollapsePanels();
}
@@ -3566,6 +3559,17 @@ public class CentralSurfacesImpl extends CoreStartable implements
}
/**
+ * Sets whether the bouncer over dream is showing. Note that the bouncer over dream is handled
+ * independently of the rest of the notification panel. As a result, setting this state via
+ * {@link #setBouncerShowing(boolean)} leads to unintended side effects from states modified
+ * behind the dream.
+ */
+ @Override
+ public void setBouncerShowingOverDream(boolean bouncerShowingOverDream) {
+ mBouncerShowingOverDream = bouncerShowingOverDream;
+ }
+
+ /**
* Propagate the bouncer state to status bar components.
*
* Separate from {@link #setBouncerShowing} because we sometimes re-create the status bar and
@@ -3913,7 +3917,8 @@ public class CentralSurfacesImpl extends CoreStartable implements
mScrimController.transitionTo(ScrimState.AOD);
} else if (mKeyguardStateController.isShowing() && !isOccluded() && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- } else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()) {
+ } else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
+ && !unlocking) {
mScrimController.transitionTo(ScrimState.DREAMING);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
@@ -4208,7 +4213,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
@Override
public boolean isBouncerShowingOverDream() {
- return isBouncerShowing() && mDreamOverlayStateController.isOverlayActive();
+ return mBouncerShowingOverDream;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 415bd90ed23a..f3ee64ff05ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Region;
+import android.os.Handler;
import android.util.Pools;
import androidx.collection.ArraySet;
@@ -29,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarState;
@@ -104,8 +106,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
KeyguardBypassController bypassController,
GroupMembershipManager groupMembershipManager,
VisualStabilityProvider visualStabilityProvider,
- ConfigurationController configurationController) {
- super(context, logger);
+ ConfigurationController configurationController,
+ @Main Handler handler) {
+ super(context, logger, handler);
Resources resources = mContext.getResources();
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
statusBarStateController.addCallback(mStatusBarStateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8792118fb9ef..8e65541081aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -216,9 +216,12 @@ public class KeyguardBouncer {
// Split up the work over multiple frames.
DejankUtils.removeCallbacks(mResetRunnable);
- if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()
- && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
- && !mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardStateController.isFaceAuthEnabled()
+ && !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ KeyguardUpdateMonitor.getCurrentUser())
+ && !needsFullscreenBouncer()
+ && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
+ && !mKeyguardBypassController.getBypassEnabled()) {
mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
} else {
DejankUtils.postAfterTraversal(mShowRunnable);
@@ -243,7 +246,7 @@ public class KeyguardBouncer {
private void onFullyShown() {
mFalsingCollector.onBouncerShown();
if (mKeyguardViewController == null) {
- Log.wtf(TAG, "onFullyShown when view was null");
+ Log.e(TAG, "onFullyShown when view was null");
} else {
mKeyguardViewController.onResume();
mContainer.announceForAccessibility(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 034fc589df97..b987f6815000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -43,7 +43,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
private var hasFaceFeature: Boolean
private var pendingUnlock: PendingUnlock? = null
private val listeners = mutableListOf<OnBypassStateChangedListener>()
- var userHasDeviceEntryIntent: Boolean = false // ie: attempted udfps auth
private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
override fun onFaceAuthEnabledChanged() = notifyListeners()
@@ -197,20 +196,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
return false
}
- /**
- * If shorter animations should be played when unlocking.
- */
- fun canPlaySubtleWindowAnimations(): Boolean {
- if (bypassEnabled) {
- return when {
- statusBarStateController.state != StatusBarState.KEYGUARD -> false
- qSExpanded -> false
- else -> true
- }
- }
- return false
- }
-
fun onStartedGoingToSleep() {
pendingUnlock = null
}
@@ -231,7 +216,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
pw.println(" launchingAffordance: $launchingAffordance")
pw.println(" qSExpanded: $qSExpanded")
pw.println(" hasFaceFeature: $hasFaceFeature")
- pw.println(" userHasDeviceEntryIntent: $userHasDeviceEntryIntent")
}
/** Registers a listener for bypass state changes. */
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 9afdfd651130..7d92c66f0a10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -646,6 +646,7 @@ public class NotificationPanelViewController extends PanelViewController {
private int mScrimCornerRadius;
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private boolean mUseLargeScreenShadeHeader;
private int mQsClipTop;
private int mQsClipBottom;
@@ -1137,18 +1138,20 @@ public class NotificationPanelViewController extends PanelViewController {
final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled;
mSplitShadeEnabled = newSplitShadeEnabled;
- boolean useLargeScreenShadeHeader =
- LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
if (mQs != null) {
mQs.setInSplitShade(mSplitShadeEnabled);
}
+
+ mUseLargeScreenShadeHeader =
+ LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
+
mLargeScreenShadeHeaderHeight =
mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
- mQuickQsHeaderHeight = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
+ mQuickQsHeaderHeight = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
- int topMargin = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
+ int topMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
- mLargeScreenShadeHeaderController.setActive(useLargeScreenShadeHeader);
+ mLargeScreenShadeHeaderController.setActive(mUseLargeScreenShadeHeader);
mAmbientState.setStackTopMargin(topMargin);
mNotificationsQSContainerController.updateResources();
@@ -2436,8 +2439,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
- * Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
- * and QS state.
+ * Updates scrim bounds, QS clipping, notifications clipping and keyguard status view clipping
+ * as well based on the bounds of the shade and QS state.
*/
private void setQSClippingBounds() {
final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
@@ -2513,6 +2516,13 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
+ /**
+ * Applies clipping to quick settings, notifications layout and
+ * updates bounds of the notifications background (notifications scrim).
+ *
+ * The parameters are bounds of the notifications area rectangle, this function
+ * calculates bounds for the QS clipping based on the notifications bounds.
+ */
private void applyQSClippingBounds(int left, int top, int right, int bottom,
boolean qsVisible) {
if (!mAnimateNextNotificationBounds || mKeyguardStatusAreaClipBounds.isEmpty()) {
@@ -2648,12 +2658,10 @@ public class NotificationPanelViewController extends PanelViewController {
if (mTransitioningToFullShadeProgress > 0.0f) {
return mTransitionToFullShadeQSPosition;
} else {
- int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
- if (qsExpansionFraction != 0.0) {
- qsBottomY = (int) MathUtils.lerp(
- qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
- }
- return qsBottomY;
+ int qsBottomYFrom = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
+ int expandedTopMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight : 0;
+ int qsBottomYTo = mQs.getDesiredHeight() + expandedTopMargin;
+ return (int) MathUtils.lerp(qsBottomYFrom, qsBottomYTo, qsExpansionFraction);
}
}
@@ -3080,9 +3088,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
private int calculatePanelHeightShade() {
- int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
- int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
-
+ final int maxHeight = mNotificationStackScrollLayoutController.getHeight();
if (mBarState == KEYGUARD) {
int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight()
+ mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
@@ -5012,7 +5018,8 @@ public class NotificationPanelViewController extends PanelViewController {
mDebugPaint.setColor(color);
canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ mView.getWidth(),
/* stopY= */ y, mDebugPaint);
- canvas.drawText(label, /* x= */ 0, /* y= */ computeDebugYTextPosition(y), mDebugPaint);
+ canvas.drawText(label + " = " + y + "px", /* x= */ 0,
+ /* y= */ computeDebugYTextPosition(y), mDebugPaint);
}
private int computeDebugYTextPosition(int lineY) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index faae4bbbafd0..a8da554d7e1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -502,7 +502,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
cb.onStateChanged(mCurrentState.mKeyguardShowing,
mCurrentState.mKeyguardOccluded,
mCurrentState.mBouncerShowing,
- mCurrentState.mDozing);
+ mCurrentState.mDozing,
+ mCurrentState.mPanelExpanded);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 82ca842d48c9..9f0ecb9d4096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -430,6 +430,8 @@ public abstract class PanelViewController {
// situations, such keeping your finger down while swiping to unlock to an app
// that is locked in landscape (the rotation will cancel the touch event).
expand = false;
+ } else if (mCentralSurfaces.isBouncerShowingOverDream()) {
+ expand = false;
} else {
// If we get a cancel, put the shade back to the state it was in when the
// gesture started
@@ -806,6 +808,7 @@ public abstract class PanelViewController {
mExpansionDragDownAmountPx = h;
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ mAmbientState.setExpansionFraction(mExpandedFraction);
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 4a5f712d587c..b447f0d36c10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -252,7 +252,7 @@ public enum ScrimState {
mBehindTint = Color.BLACK;
mBlankScreen = false;
- if (previousState == ScrimState.AOD) {
+ if (mDisplayRequiresBlanking && previousState == ScrimState.AOD) {
// Set all scrims black, before they fade transparent.
updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 61e123a8e42a..e3c070e3686e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -20,7 +20,6 @@ import static android.view.WindowInsets.Type.navigationBars;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_COLLAPSING;
-import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@@ -164,6 +163,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void onVisibilityChanged(boolean isVisible) {
+ mCentralSurfaces
+ .setBouncerShowingOverDream(
+ isVisible && mDreamOverlayStateController.isOverlayActive());
+
if (!isVisible) {
mCentralSurfaces.setBouncerHiddenFraction(KeyguardBouncer.EXPANSION_HIDDEN);
}
@@ -832,46 +835,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
executeAfterKeyguardGoneAction();
boolean wakeUnlockPulsing =
mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
- boolean needsFading = needsBypassFading();
- if (needsFading) {
- delay = 0;
- fadeoutDuration = KeyguardBypassController.BYPASS_FADE_DURATION;
- } else if (wakeUnlockPulsing) {
- delay = 0;
- fadeoutDuration = 240;
- }
- mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading);
+ mCentralSurfaces.setKeyguardFadingAway(startTime, delay, 0);
mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
- if (needsFading) {
- ViewGroupFadeHelper.fadeOutAllChildrenExcept(
- mNotificationPanelViewController.getView(),
- mNotificationContainer,
- fadeoutDuration,
- () -> {
- mCentralSurfaces.hideKeyguard();
- onKeyguardFadedAway();
- });
- } else {
- mCentralSurfaces.fadeKeyguardWhilePulsing();
- }
+ mCentralSurfaces.fadeKeyguardWhilePulsing();
wakeAndUnlockDejank();
} else {
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
if (!staying) {
mNotificationShadeWindowController.setKeyguardFadingAway(true);
- if (needsFading) {
- ViewGroupFadeHelper.fadeOutAllChildrenExcept(
- mNotificationPanelViewController.getView(),
- mNotificationContainer,
- fadeoutDuration,
- () -> {
- mCentralSurfaces.hideKeyguard();
- });
- } else {
- mCentralSurfaces.hideKeyguard();
- }
+ mCentralSurfaces.hideKeyguard();
// hide() will happen asynchronously and might arrive after the scrims
// were already hidden, this means that the transition callback won't
// be triggered anymore and StatusBarWindowController will be forever in
@@ -884,6 +858,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBiometricUnlockController.finishKeyguardFadingAway();
}
}
+
updateStates();
mNotificationShadeWindowController.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
@@ -893,13 +868,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
Trace.endSection();
}
- private boolean needsBypassFading() {
- return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING
- || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING
- || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK)
- && mBypassController.getBypassEnabled();
- }
-
@Override
public void onNavigationModeChanged(int mode) {
boolean gesturalNav = QuickStepContract.isGesturalMode(mode);
@@ -1186,7 +1154,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public boolean shouldSubtleWindowAnimationsForUnlock() {
- return needsBypassFading();
+ return false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index ac43b679da0f..ae48c2d3b6f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -17,5 +17,5 @@ package com.android.systemui.statusbar.phone;
public interface StatusBarWindowCallback {
void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
- boolean isDozing);
+ boolean isDozing, boolean panelExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 36a045637a87..6e331bc13294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -61,10 +61,10 @@ import java.util.List;
* and dismisses itself when it receives the broadcast.
*/
public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigChangedCallback {
+ protected static final int DEFAULT_THEME = R.style.Theme_SystemUI_Dialog;
// TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
private static final String FLAG_TABLET_DIALOG_WIDTH =
"persist.systemui.flag_tablet_dialog_width";
- private static final int DEFAULT_THEME = R.style.Theme_SystemUI_Dialog;
private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
private final Context mContext;
@@ -88,10 +88,6 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
this(context, theme, DEFAULT_DISMISS_ON_DEVICE_LOCK);
}
- public SystemUIDialog(Context context, boolean dismissOnDeviceLock) {
- this(context, DEFAULT_THEME, dismissOnDeviceLock);
- }
-
public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
super(context, theme);
mContext = context;
@@ -436,4 +432,5 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
mDialog.dismiss();
}
}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 06532c4f9d17..61051c2856ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -38,7 +38,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.OperatorNameViewController;
-import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -261,7 +260,6 @@ public abstract class StatusBarViewModule {
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
NotificationPanelViewController notificationPanelViewController,
- NetworkController networkController,
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CarrierConfigTracker carrierConfigTracker,
@@ -281,7 +279,6 @@ public abstract class StatusBarViewModule {
statusBarHideIconsForBouncerManager,
keyguardStateController,
notificationPanelViewController,
- networkController,
statusBarStateController,
commandQueue,
carrierConfigTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 597c949168d4..670ba96ca1ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -53,9 +53,6 @@ import com.android.systemui.statusbar.DisableFlagsLogger.DisableState;
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.connectivity.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -69,7 +66,6 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListener;
@@ -101,7 +97,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
private final NotificationPanelViewController mNotificationPanelViewController;
- private final NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
private View mOngoingCallChip;
@@ -127,13 +122,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private List<String> mBlockedIcons = new ArrayList<>();
- private SignalCallback mSignalCallback = new SignalCallback() {
- @Override
- public void setIsAirplaneMode(@NonNull IconState icon) {
- mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
- }
- };
-
private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() {
@Override
public void onOngoingCallStateChanged(boolean animate) {
@@ -178,7 +166,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
NotificationPanelViewController notificationPanelViewController,
- NetworkController networkController,
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CarrierConfigTracker carrierConfigTracker,
@@ -198,7 +185,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mKeyguardStateController = keyguardStateController;
mNotificationPanelViewController = notificationPanelViewController;
- mNetworkController = networkController;
mStatusBarStateController = statusBarStateController;
mCommandQueue = commandQueue;
mCarrierConfigTracker = carrierConfigTracker;
@@ -237,7 +223,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
showSystemIconArea(false);
showClock(false);
- initEmergencyCryptkeeperText();
initOperatorName();
initNotificationIconArea();
mSystemEventAnimator =
@@ -316,9 +301,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public void onDestroyView() {
super.onDestroyView();
mStatusBarIconController.removeIconGroup(mDarkIconManager);
- if (mNetworkController.hasEmergencyCryptKeeperText()) {
- mNetworkController.removeCallback(mSignalCallback);
- }
mCarrierConfigTracker.removeCallback(mCarrierConfigCallback);
mCarrierConfigTracker.removeDataSubscriptionChangedListener(mDefaultDataListener);
}
@@ -414,15 +396,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
- if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
- if (mNetworkController.hasEmergencyCryptKeeperText()) {
- state |= DISABLE_NOTIFICATION_ICONS;
- }
- if (!mNetworkController.isRadioOn()) {
- state |= DISABLE_SYSTEM_INFO;
- }
- }
-
// The shelf will be hidden when dozing with a custom clock, we must show notification
// icons in this occasion.
if (mStatusBarStateController.isDozing()
@@ -593,19 +566,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
}
- private void initEmergencyCryptkeeperText() {
- View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text);
- if (mNetworkController.hasEmergencyCryptKeeperText()) {
- if (emergencyViewStub != null) {
- ((ViewStub) emergencyViewStub).inflate();
- }
- mNetworkController.addCallback(mSignalCallback);
- } else if (emergencyViewStub != null) {
- ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
- parent.removeView(emergencyViewStub);
- }
- }
-
private void initOperatorName() {
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
if (mCarrierConfigTracker.getShowOperatorNameInStatusBarConfig(subId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionChangeEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionChangeEvent.kt
index c0384b444511..7c61b299cff9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionChangeEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionChangeEvent.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.systemui.statusbar.phone.panelstate
import android.annotation.FloatRange
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
deleted file mode 100644
index f2ee85886dca..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2016 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.policy;
-
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
-
-import java.util.List;
-
-public class EmergencyCryptkeeperText extends TextView {
-
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onPhoneStateChanged(int phoneState) {
- update();
- }
-
- @Override
- public void onRefreshCarrierInfo() {
- update();
- }
- };
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
- update();
- }
- }
- };
-
- public EmergencyCryptkeeperText(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- setVisibility(GONE);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
- mKeyguardUpdateMonitor.registerCallback(mCallback);
- getContext().registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
- update();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (mKeyguardUpdateMonitor != null) {
- mKeyguardUpdateMonitor.removeCallback(mCallback);
- }
- getContext().unregisterReceiver(mReceiver);
- }
-
- private boolean iccCardExist(int simState) {
- return ((simState == TelephonyManager.SIM_STATE_PIN_REQUIRED)
- || (simState == TelephonyManager.SIM_STATE_PUK_REQUIRED)
- || (simState == TelephonyManager.SIM_STATE_NETWORK_LOCKED)
- || (simState == TelephonyManager.SIM_STATE_READY)
- || (simState == TelephonyManager.SIM_STATE_NOT_READY)
- || (simState == TelephonyManager.SIM_STATE_PERM_DISABLED)
- || (simState == TelephonyManager.SIM_STATE_CARD_IO_ERROR)
- || (simState == TelephonyManager.SIM_STATE_CARD_RESTRICTED)
- || (simState == TelephonyManager.SIM_STATE_LOADED));
- }
-
- public void update() {
- boolean hasMobile = mContext.getSystemService(TelephonyManager.class).isDataCapable();
- boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
-
- if (!hasMobile || airplaneMode) {
- setText(null);
- setVisibility(GONE);
- return;
- }
-
- boolean allSimsMissing = true;
- CharSequence displayText = null;
-
- List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
- final int N = subs.size();
- for (int i = 0; i < N; i++) {
- int subId = subs.get(i).getSubscriptionId();
- int simState = mKeyguardUpdateMonitor.getSimState(subId);
- CharSequence carrierName = subs.get(i).getCarrierName();
- if (iccCardExist(simState) && !TextUtils.isEmpty(carrierName)) {
- allSimsMissing = false;
- displayText = carrierName;
- }
- }
- if (allSimsMissing) {
- if (N != 0) {
- // Shows "Emergency calls only" on devices that are voice-capable.
- // This depends on mPlmn containing the text "Emergency calls only" when the radio
- // has some connectivity. Otherwise it should show "No service"
- // Grab the first subscription, because they all should contain the emergency text,
- // described above.
- displayText = subs.get(0).getCarrierName();
- } else {
- // We don't have a SubscriptionInfo to get the emergency calls only from.
- // Grab it from the old sticky broadcast if possible instead. We can use it
- // here because no subscriptions are active, so we don't have
- // to worry about MSIM clashing.
- displayText = getContext().getText(
- com.android.internal.R.string.emergency_calls_only);
- Intent i = getContext().registerReceiver(null,
- new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED));
- if (i != null) {
- displayText = i.getStringExtra(TelephonyManager.EXTRA_PLMN);
- }
- }
- }
-
- setText(displayText);
- setVisibility(TextUtils.isEmpty(displayText) ? GONE : VISIBLE);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
deleted file mode 100644
index 9c099f91bc8d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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.policy;
-
-import android.sysprop.VoldProperties;
-
-/**
- * Helper for determining whether the phone is decrypted yet.
- */
-public class EncryptionHelper {
-
- public static final boolean IS_DATA_ENCRYPTED = isDataEncrypted();
-
- private static boolean isDataEncrypted() {
- String voldState = VoldProperties.decrypt().orElse("");
- return "1".equals(voldState) || "trigger_restart_min_framework".equals(voldState);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index bce5a159f79c..e5d5ed48cc9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -24,6 +24,7 @@ import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.os.Handler;
import android.provider.Settings;
import android.util.ArrayMap;
import android.view.accessibility.AccessibilityManager;
@@ -34,6 +35,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -79,8 +81,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
}
}
- public HeadsUpManager(@NonNull final Context context, HeadsUpManagerLogger logger) {
- super(logger);
+ public HeadsUpManager(@NonNull final Context context, HeadsUpManagerLogger logger,
+ @Main Handler handler) {
+ super(logger, handler);
mContext = context;
mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
mUiEventLogger = Dependency.get(UiEventLogger.class);
@@ -94,7 +97,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
mSnoozeLengthMs = Settings.Global.getInt(context.getContentResolver(),
SETTING_HEADS_UP_SNOOZE_LENGTH_MS, defaultSnoozeLengthMs);
- ContentObserver settingsObserver = new ContentObserver(mHandler) {
+ ContentObserver settingsObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
final int packageSnoozeLengthMs = Settings.Global.getInt(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index dce24122aa7e..250d9d46de66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -109,28 +109,15 @@ public interface KeyguardStateController extends CallbackController<Callback> {
* we're bypassing
*/
default long getShortenedFadingAwayDuration() {
- if (isBypassFadingAnimation()) {
- return getKeyguardFadingAwayDuration();
- } else {
- return getKeyguardFadingAwayDuration() / 2;
- }
- }
-
- /**
- * @return {@code true} if the current fading away animation is the fast bypass fading.
- */
- default boolean isBypassFadingAnimation() {
- return false;
+ return getKeyguardFadingAwayDuration() / 2;
}
/**
* Notifies that the Keyguard is fading away with the specified timings.
* @param delay the precalculated animation delay in milliseconds
* @param fadeoutDuration the duration of the exit animation, in milliseconds
- * @param isBypassFading is this a fading away animation while bypassing
*/
- default void notifyKeyguardFadingAway(long delay, long fadeoutDuration,
- boolean isBypassFading) {
+ default void notifyKeyguardFadingAway(long delay, long fadeoutDuratio) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 2a225b909f90..2fb16ee9b3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -72,7 +72,6 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
private long mKeyguardFadingAwayDuration;
private boolean mKeyguardGoingAway;
private boolean mLaunchTransitionFadingAway;
- private boolean mBypassFadingAnimation;
private boolean mTrustManaged;
private boolean mTrusted;
private boolean mDebugUnlocked = false;
@@ -203,10 +202,9 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
}
@Override
- public void notifyKeyguardFadingAway(long delay, long fadeoutDuration, boolean isBypassFading) {
+ public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
- mBypassFadingAnimation = isBypassFading;
setKeyguardFadingAway(true);
}
@@ -284,11 +282,6 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
}
@Override
- public boolean isBypassFadingAnimation() {
- return mBypassFadingAnimation;
- }
-
- @Override
public long getKeyguardFadingAwayDelay() {
return mKeyguardFadingAwayDelay;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 1b685d0aad7a..6af8e9e77d10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -45,6 +45,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyCallback;
import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -63,6 +64,7 @@ import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.users.UserCreatingDialog;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Dumpable;
+import com.android.systemui.GuestResetOrExitSessionReceiver;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
@@ -121,6 +123,8 @@ public class UserSwitcherController implements Dumpable {
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
@VisibleForTesting
final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
+ @VisibleForTesting
+ final GuestResetOrExitSessionReceiver mGuestResetOrExitSessionReceiver;
private final KeyguardStateController mKeyguardStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
private final DevicePolicyManager mDevicePolicyManager;
@@ -188,7 +192,9 @@ public class UserSwitcherController implements Dumpable {
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker,
DumpManager dumpManager,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ DialogLaunchAnimator dialogLaunchAnimator,
+ GuestResumeSessionReceiver guestResumeSessionReceiver,
+ GuestResetOrExitSessionReceiver guestResetOrExitSessionReceiver) {
mContext = context;
mActivityManager = activityManager;
mUserTracker = userTracker;
@@ -199,15 +205,14 @@ public class UserSwitcherController implements Dumpable {
mFalsingManager = falsingManager;
mInteractionJankMonitor = interactionJankMonitor;
mLatencyTracker = latencyTracker;
+ mGuestResumeSessionReceiver = guestResumeSessionReceiver;
+ mGuestResetOrExitSessionReceiver = guestResetOrExitSessionReceiver;
mGlobalSettings = globalSettings;
- mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
- this, mUserTracker, mUiEventLogger, secureSettings);
mBgExecutor = bgExecutor;
mLongRunningExecutor = longRunningExecutor;
mUiExecutor = uiExecutor;
- if (!UserManager.isGuestUserEphemeral()) {
- mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
- }
+ mGuestResumeSessionReceiver.register();
+ mGuestResetOrExitSessionReceiver.register();
mGuestUserAutoCreated = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_guestUserAutoCreated);
mGuestIsResetting = new AtomicBoolean();
@@ -278,6 +283,10 @@ public class UserSwitcherController implements Dumpable {
refreshUsers(UserHandle.USER_NULL);
}
+ private static boolean isEnableGuestModeUxChanges(Context context) {
+ return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_GUEST_MODE_UX_CHANGES);
+ }
+
/**
* Refreshes users from UserManager.
*
@@ -524,20 +533,31 @@ public class UserSwitcherController implements Dumpable {
private void onUserListItemClicked(int id, UserRecord record, DialogShower dialogShower) {
int currUserId = mUserTracker.getUserId();
+ // If switching from guest and guest is ephemeral, then follow the flow
+ // of showExitGuestDialog to remove current guest,
+ // and switch to selected user
+ UserInfo currUserInfo = mUserTracker.getUserInfo();
if (currUserId == id) {
if (record.isGuest) {
- showExitGuestDialog(id, dialogShower);
+ showExitGuestDialog(id, currUserInfo.isEphemeral(), dialogShower);
}
return;
}
- if (UserManager.isGuestUserEphemeral()) {
- // If switching from guest, we want to bring up the guest exit dialog instead of switching
- UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
- if (currUserInfo != null && currUserInfo.isGuest()) {
- showExitGuestDialog(currUserId, record.resolveId(), dialogShower);
+
+ if (currUserInfo != null && currUserInfo.isGuest()) {
+ if (isEnableGuestModeUxChanges(mContext)) {
+ showExitGuestDialog(currUserId, currUserInfo.isEphemeral(),
+ record.resolveId(), dialogShower);
return;
+ } else {
+ if (currUserInfo.isEphemeral()) {
+ showExitGuestDialog(currUserId, currUserInfo.isEphemeral(),
+ record.resolveId(), dialogShower);
+ return;
+ }
}
}
+
if (dialogShower != null) {
// If we haven't morphed into another dialog, it means we have just switched users.
// Then, dismiss the dialog.
@@ -559,7 +579,7 @@ public class UserSwitcherController implements Dumpable {
}
}
- private void showExitGuestDialog(int id, DialogShower dialogShower) {
+ private void showExitGuestDialog(int id, boolean isGuestEphemeral, DialogShower dialogShower) {
int newId = UserHandle.USER_SYSTEM;
if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
@@ -567,14 +587,15 @@ public class UserSwitcherController implements Dumpable {
newId = info.id;
}
}
- showExitGuestDialog(id, newId, dialogShower);
+ showExitGuestDialog(id, isGuestEphemeral, newId, dialogShower);
}
- private void showExitGuestDialog(int id, int targetId, DialogShower dialogShower) {
+ private void showExitGuestDialog(int id, boolean isGuestEphemeral,
+ int targetId, DialogShower dialogShower) {
if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
mExitGuestDialog.cancel();
}
- mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId);
+ mExitGuestDialog = new ExitGuestDialog(mContext, id, isGuestEphemeral, targetId);
if (dialogShower != null) {
dialogShower.showDialog(mExitGuestDialog);
} else {
@@ -808,6 +829,52 @@ public class UserSwitcherController implements Dumpable {
}
}
+ /**
+ * Exits guest user and switches to previous non-guest user. The guest must be the current
+ * user.
+ *
+ * @param guestUserId user id of the guest user to exit
+ * @param targetUserId user id of the guest user to exit, set to UserHandle.USER_NULL when
+ * target user id is not known
+ * @param forceRemoveGuestOnExit true: remove guest before switching user,
+ * false: remove guest only if its ephemeral, else keep guest
+ */
+ public void exitGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId,
+ boolean forceRemoveGuestOnExit) {
+ UserInfo currentUser = mUserTracker.getUserInfo();
+ if (currentUser.id != guestUserId) {
+ Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
+ + " is not current user (" + currentUser.id + ")");
+ return;
+ }
+ if (!currentUser.isGuest()) {
+ Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
+ + " is not a guest");
+ return;
+ }
+
+ int newUserId = UserHandle.USER_SYSTEM;
+ if (targetUserId == UserHandle.USER_NULL) {
+ // when target user is not specified switch to last non guest user
+ if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
+ UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
+ if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
+ newUserId = info.id;
+ }
+ }
+ } else {
+ newUserId = targetUserId;
+ }
+
+ if (currentUser.isEphemeral() || forceRemoveGuestOnExit) {
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
+ removeGuestUser(currentUser.id, newUserId);
+ } else {
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH);
+ switchToUserId(newUserId);
+ }
+ }
+
private void scheduleGuestCreation() {
if (!mGuestCreationScheduled.compareAndSet(false, true)) {
return;
@@ -975,9 +1042,14 @@ public class UserSwitcherController implements Dumpable {
public String getName(Context context, UserRecord item) {
if (item.isGuest) {
if (item.isCurrent) {
- return context.getString(mController.mGuestUserAutoCreated
+ if (isEnableGuestModeUxChanges(context)) {
+ return context.getString(
+ com.android.settingslib.R.string.guest_exit_quick_settings_button);
+ } else {
+ return context.getString(mController.mGuestUserAutoCreated
? com.android.settingslib.R.string.guest_reset_guest
: com.android.settingslib.R.string.guest_exit_guest);
+ }
} else {
if (item.info != null) {
return context.getString(com.android.internal.R.string.guest_name);
@@ -994,8 +1066,13 @@ public class UserSwitcherController implements Dumpable {
? com.android.settingslib.R.string.guest_resetting
: com.android.internal.R.string.guest_name);
} else {
- return context.getString(
- com.android.settingslib.R.string.guest_new_guest);
+ if (isEnableGuestModeUxChanges(context)) {
+ // we always show "guest" as string, instead of "add guest"
+ return context.getString(com.android.internal.R.string.guest_name);
+ } else {
+ return context.getString(
+ com.android.settingslib.R.string.guest_new_guest);
+ }
}
}
}
@@ -1017,7 +1094,11 @@ public class UserSwitcherController implements Dumpable {
protected static Drawable getIconDrawable(Context context, UserRecord item) {
int iconRes;
if (item.isAddUser) {
- iconRes = R.drawable.ic_account_circle_filled;
+ if (isEnableGuestModeUxChanges(context)) {
+ iconRes = R.drawable.ic_add;
+ } else {
+ iconRes = R.drawable.ic_account_circle_filled;
+ }
} else if (item.isGuest) {
iconRes = R.drawable.ic_account_circle;
} else if (item.isAddSupervisedUser) {
@@ -1189,24 +1270,58 @@ public class UserSwitcherController implements Dumpable {
private final int mGuestId;
private final int mTargetId;
+ private final boolean mIsGuestEphemeral;
- public ExitGuestDialog(Context context, int guestId, int targetId) {
+ ExitGuestDialog(Context context, int guestId, boolean isGuestEphemeral,
+ int targetId) {
super(context);
- setTitle(mGuestUserAutoCreated
- ? com.android.settingslib.R.string.guest_reset_guest_dialog_title
- : com.android.settingslib.R.string.guest_remove_guest_dialog_title);
- setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
- setButton(DialogInterface.BUTTON_NEUTRAL,
- context.getString(android.R.string.cancel), this);
- setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(mGuestUserAutoCreated
+ if (isEnableGuestModeUxChanges(context)) {
+ if (isGuestEphemeral) {
+ setTitle(context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_title));
+ setMessage(context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_message));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_button), this);
+ } else {
+ setTitle(context.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_title_non_ephemeral));
+ setMessage(context.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_message_non_ephemeral));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_clear_data_button),
+ this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(
+ com.android.settingslib.R.string.guest_exit_save_data_button),
+ this);
+ }
+ } else {
+ setTitle(mGuestUserAutoCreated
+ ? com.android.settingslib.R.string.guest_reset_guest_dialog_title
+ : com.android.settingslib.R.string.guest_remove_guest_dialog_title);
+ setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ context.getString(android.R.string.cancel), this);
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(mGuestUserAutoCreated
? com.android.settingslib.R.string.guest_reset_guest_confirm_button
: com.android.settingslib.R.string.guest_remove_guest_confirm_button),
- this);
+ this);
+ }
SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
setCanceledOnTouchOutside(false);
mGuestId = guestId;
mTargetId = targetId;
+ mIsGuestEphemeral = isGuestEphemeral;
}
@Override
@@ -1216,12 +1331,40 @@ public class UserSwitcherController implements Dumpable {
if (mFalsingManager.isFalseTap(penalty)) {
return;
}
- if (which == BUTTON_NEUTRAL) {
- cancel();
+ if (isEnableGuestModeUxChanges(getContext())) {
+ if (mIsGuestEphemeral) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mDialogLaunchAnimator.dismissStack(this);
+ // Ephemeral guest: exit guest, guest is removed by the system
+ // on exit, since its marked ephemeral
+ exitGuestUser(mGuestId, mTargetId, false);
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ // Cancel clicked, do nothing
+ cancel();
+ }
+ } else {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mDialogLaunchAnimator.dismissStack(this);
+ // Non-ephemeral guest: exit guest, guest is not removed by the system
+ // on exit, since its marked non-ephemeral
+ exitGuestUser(mGuestId, mTargetId, false);
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ mDialogLaunchAnimator.dismissStack(this);
+ // Non-ephemeral guest: remove guest and then exit
+ exitGuestUser(mGuestId, mTargetId, true);
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ // Cancel clicked, do nothing
+ cancel();
+ }
+ }
} else {
- mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
- mDialogLaunchAnimator.dismissStack(this);
- removeGuestUser(mGuestId, mTargetId);
+ if (which == BUTTON_NEUTRAL) {
+ cancel();
+ } else {
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
+ mDialogLaunchAnimator.dismissStack(this);
+ removeGuestUser(mGuestId, mTargetId);
+ }
}
}
}
@@ -1230,10 +1373,17 @@ public class UserSwitcherController implements Dumpable {
final class AddUserDialog extends SystemUIDialog implements
DialogInterface.OnClickListener {
- public AddUserDialog(Context context) {
+ AddUserDialog(Context context) {
super(context);
+
setTitle(com.android.settingslib.R.string.user_add_user_title);
- setMessage(com.android.settingslib.R.string.user_add_user_message_short);
+ String message = context.getString(
+ com.android.settingslib.R.string.user_add_user_message_short);
+ UserInfo currentUser = mUserTracker.getUserInfo();
+ if (currentUser != null && currentUser.isGuest() && currentUser.isEphemeral()) {
+ message += context.getString(R.string.user_add_user_message_guest_remove);
+ }
+ setMessage(message);
setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 9a19d8d11190..22c192d0f28c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -168,7 +168,8 @@ public abstract class TvSystemUIModule {
KeyguardBypassController bypassController,
GroupMembershipManager groupManager,
VisualStabilityProvider visualStabilityProvider,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ @Main Handler handler) {
return new HeadsUpManagerPhone(
context,
headsUpManagerLogger,
@@ -176,7 +177,8 @@ public abstract class TvSystemUIModule {
bypassController,
groupManager,
visualStabilityProvider,
- configurationController
+ configurationController,
+ handler
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index d2d2361d613d..eea6ac0e72e9 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.view.IWindowManager
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.system.SystemUnfoldSharedModule
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
@@ -34,7 +35,7 @@ import java.util.Optional
import javax.inject.Named
import javax.inject.Singleton
-@Module(includes = [UnfoldSharedModule::class])
+@Module(includes = [UnfoldSharedModule::class, SystemUnfoldSharedModule::class])
class UnfoldTransitionModule {
@Provides @UnfoldTransitionATracePrefix fun tracingTagPrefix() = "systemui"
@@ -62,11 +63,6 @@ class UnfoldTransitionModule {
@Provides
@Singleton
- fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
- createConfig(context)
-
- @Provides
- @Singleton
fun provideNaturalRotationProgressProvider(
context: Context,
windowManager: IWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 76dfcb182e97..53da213eb38e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -35,11 +35,15 @@ import javax.inject.Inject;
public class NotificationChannels extends CoreStartable {
public static String ALERTS = "ALR";
public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP";
- public static String GENERAL = "GEN";
+ // Deprecated. Please use or create a more specific channel that users will better understand
+ @Deprecated
+ static String GENERAL = "GEN";
public static String STORAGE = "DSK";
public static String BATTERY = "BAT";
public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP"
public static String HINTS = "HNT";
+ public static String INSTANT = "INS";
+ public static String SETUP = "STP";
@Inject
public NotificationChannels(Context context) {
@@ -64,11 +68,17 @@ public class NotificationChannels extends CoreStartable {
context.getString(R.string.notification_channel_alerts),
NotificationManager.IMPORTANCE_HIGH);
- final NotificationChannel general = new NotificationChannel(
- GENERAL,
- context.getString(R.string.notification_channel_general),
+ final NotificationChannel instant = new NotificationChannel(
+ INSTANT,
+ context.getString(R.string.notification_channel_instant),
NotificationManager.IMPORTANCE_MIN);
+ final NotificationChannel setup = new NotificationChannel(
+ SETUP,
+ context.getString(R.string.notification_channel_setup),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ setup.setSound(null, null);
+
final NotificationChannel storage = new NotificationChannel(
STORAGE,
context.getString(R.string.notification_channel_storage),
@@ -84,7 +94,8 @@ public class NotificationChannels extends CoreStartable {
nm.createNotificationChannels(Arrays.asList(
alerts,
- general,
+ instant,
+ setup,
storage,
createScreenshotChannel(
context.getString(R.string.notification_channel_screenshot)),
@@ -123,6 +134,11 @@ public class NotificationChannels extends CoreStartable {
@Override
public void start() {
createAll(mContext);
+ cleanUp();
+ }
+
+ private void cleanUp() {
+ mContext.getSystemService(NotificationManager.class).deleteNotificationChannel(GENERAL);
}
private static boolean isTv(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
index d3c6e9aa0da9..313d56febb75 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
@@ -18,6 +18,7 @@ package com.android.systemui.util.condition;
import android.util.Log;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.CallbackController;
import org.jetbrains.annotations.NotNull;
@@ -60,21 +61,13 @@ public class Monitor implements CallbackController<Monitor.Callback> {
};
@Inject
- public Monitor(Executor executor, Set<Condition> conditions, Set<Callback> callbacks) {
+ public Monitor(@Main Executor executor, Set<Condition> conditions) {
mConditions = new HashSet<>();
mExecutor = executor;
if (conditions != null) {
mConditions.addAll(conditions);
}
-
- if (callbacks == null) {
- return;
- }
-
- for (Callback callback : callbacks) {
- addCallbackLocked(callback);
- }
}
private void updateConditionMetState() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java b/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
index fc67973fe278..8e739d61b4f2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
@@ -34,8 +34,7 @@ public interface MonitorComponent {
*/
@Subcomponent.Factory
interface Factory {
- MonitorComponent create(@BindsInstance Set<Condition> conditions,
- @BindsInstance Set<Monitor.Callback> callbacks);
+ MonitorComponent create(@BindsInstance Set<Condition> conditions);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 83fc28189db5..e90775de591a 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -78,6 +78,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -121,6 +122,7 @@ public class BubblesManager implements Dumpable {
private final Bubbles.SysuiProxy mSysuiProxy;
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
+ private final StatusBarWindowCallback mStatusBarWindowCallback;
/**
* Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
@@ -278,9 +280,15 @@ public class BubblesManager implements Dumpable {
});
+ // Store callback in a field so it won't get GC'd
+ mStatusBarWindowCallback =
+ (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) ->
+ mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
+ notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
+
mSysuiProxy = new Bubbles.SysuiProxy() {
@Override
- public void isNotificationShadeExpand(Consumer<Boolean> callback) {
+ public void isNotificationPanelExpand(Consumer<Boolean> callback) {
sysuiMainExecutor.execute(() -> {
callback.accept(mNotificationShadeWindowController.getPanelExpanded());
});
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
index e42d537596c5..603cf3bcef74 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
@@ -18,6 +18,7 @@ package com.android.keyguard
import android.graphics.Bitmap
import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.Typeface
import android.graphics.fonts.Font
import android.graphics.fonts.FontFamily
@@ -194,6 +195,128 @@ class TextInterpolatorTest : SysuiTestCase() {
assertThat(expected.sameAs(actual)).isTrue()
}
+
+ @Test
+ fun testGlyphCallback_Empty() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout).apply {
+ glyphFilter = { glyph, progress ->
+ }
+ }
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
+
+ @Test
+ fun testGlyphCallback_Xcoordinate() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout).apply {
+ glyphFilter = { glyph, progress ->
+ glyph.x += 30f
+ }
+ }
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ // The glyph position was modified by callback, so the bitmap should not be the same.
+ // We cannot modify the result of StaticLayout, so we cannot expect the exact bitmaps.
+ assertThat(expected.sameAs(actual)).isFalse()
+ }
+
+ @Test
+ fun testGlyphCallback_Ycoordinate() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout).apply {
+ glyphFilter = { glyph, progress ->
+ glyph.y += 30f
+ }
+ }
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ // The glyph position was modified by callback, so the bitmap should not be the same.
+ // We cannot modify the result of StaticLayout, so we cannot expect the exact bitmaps.
+ assertThat(expected.sameAs(actual)).isFalse()
+ }
+
+ @Test
+ fun testGlyphCallback_TextSize() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout).apply {
+ glyphFilter = { glyph, progress ->
+ glyph.textSize += 10f
+ }
+ }
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ // The glyph position was modified by callback, so the bitmap should not be the same.
+ // We cannot modify the result of StaticLayout, so we cannot expect the exact bitmaps.
+ assertThat(expected.sameAs(actual)).isFalse()
+ }
+
+ @Test
+ fun testGlyphCallback_Color() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout).apply {
+ glyphFilter = { glyph, progress ->
+ glyph.color = Color.RED
+ }
+ }
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT, TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ // The glyph position was modified by callback, so the bitmap should not be the same.
+ // We cannot modify the result of StaticLayout, so we cannot expect the exact bitmaps.
+ assertThat(expected.sameAs(actual)).isFalse()
+ }
}
private fun Layout.toBitmap(width: Int, height: Int) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 21c3d6ea0660..08503308209b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -38,6 +38,7 @@ import android.testing.AndroidTestingRunner;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.animation.AccelerateInterpolator;
@@ -761,8 +762,16 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
WindowMagnifierCallback callback, SysUiState sysUiState) {
- super(context, handler, animationController, sfVsyncFrameProvider, mirrorWindowControl,
- transaction, callback, sysUiState);
+ super(
+ context,
+ handler,
+ animationController,
+ sfVsyncFrameProvider,
+ mirrorWindowControl,
+ transaction,
+ callback,
+ sysUiState,
+ WindowManagerGlobal::getWindowSession);
mSpyController = Mockito.mock(WindowMagnificationController.class);
}
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 b7d345965d36..3d77d64a7988 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -28,6 +28,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -53,18 +54,23 @@ import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.RegionIterator;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.text.TextUtils;
import android.view.Display;
+import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
@@ -120,9 +126,10 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
private final ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0, 1.0f).setDuration(0);
+ private IWindowSession mWindowSessionSpy;
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mContext = Mockito.spy(getContext());
mHandler = new FakeHandler(TestableLooper.get(this).getLooper());
@@ -130,6 +137,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
final WindowManager wm = mContext.getSystemService(WindowManager.class);
mWindowManager = spy(new TestableWindowManager(wm));
+ mWindowSessionSpy = spy(WindowManagerGlobal.getWindowSession());
+
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
doAnswer(invocation -> {
FrameCallback callback = invocation.getArgument(0);
@@ -142,9 +151,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
mResources = getContext().getOrCreateTestableResources().getResources();
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
mContext, mValueAnimator);
- mWindowMagnificationController = new WindowMagnificationController(mContext,
- mHandler, mWindowMagnificationAnimationController, mSfVsyncFrameProvider,
- mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
+ mWindowMagnificationController =
+ new WindowMagnificationController(
+ mContext,
+ mHandler,
+ mWindowMagnificationAnimationController,
+ mSfVsyncFrameProvider,
+ mMirrorWindowControl,
+ mTransaction,
+ mWindowMagnifierCallback,
+ mSysUiState,
+ () -> mWindowSessionSpy);
verify(mMirrorWindowControl).setWindowDelegate(
any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -716,6 +733,77 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}
@Test
+ public void moveWindowMagnificationToRightEdge_dragHandleMovesToLeftAndUpdatesTapExcludeRegion()
+ throws RemoteException {
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ setSystemGestureInsets();
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(
+ Float.NaN, Float.NaN, Float.NaN);
+ });
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mWindowMagnificationController.moveWindowMagnifier(bounds.width(), 0);
+ });
+
+ // Wait for Region updated.
+ waitForIdleSync();
+
+ final ArgumentCaptor<Region> tapExcludeRegionCapturer =
+ ArgumentCaptor.forClass(Region.class);
+ verify(mWindowSessionSpy, times(2))
+ .updateTapExcludeRegion(any(), tapExcludeRegionCapturer.capture());
+ Region tapExcludeRegion = tapExcludeRegionCapturer.getValue();
+ RegionIterator iterator = new RegionIterator(tapExcludeRegion);
+
+ final Rect topRect = new Rect();
+ final Rect bottomRect = new Rect();
+ assertTrue(iterator.next(topRect));
+ assertTrue(iterator.next(bottomRect));
+ assertFalse(iterator.next(new Rect()));
+
+ assertEquals(topRect.right, bottomRect.right);
+ assertNotEquals(topRect.left, bottomRect.left);
+ }
+
+ @Test
+ public void moveWindowMagnificationToLeftEdge_dragHandleMovesToRightAndUpdatesTapExcludeRegion()
+ throws RemoteException {
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ setSystemGestureInsets();
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(
+ Float.NaN, Float.NaN, Float.NaN);
+ });
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mWindowMagnificationController.moveWindowMagnifier(-bounds.width(), 0);
+ });
+
+ // Wait for Region updated.
+ waitForIdleSync();
+
+ final ArgumentCaptor<Region> tapExcludeRegionCapturer =
+ ArgumentCaptor.forClass(Region.class);
+ verify(mWindowSessionSpy).updateTapExcludeRegion(any(), tapExcludeRegionCapturer.capture());
+ Region tapExcludeRegion = tapExcludeRegionCapturer.getValue();
+ RegionIterator iterator = new RegionIterator(tapExcludeRegion);
+
+ final Rect topRect = new Rect();
+ final Rect bottomRect = new Rect();
+ assertTrue(iterator.next(topRect));
+ assertTrue(iterator.next(bottomRect));
+ assertFalse(iterator.next(new Rect()));
+
+ assertEquals(topRect.left, bottomRect.left);
+ assertNotEquals(topRect.right, bottomRect.right);
+ }
+
+ @Test
public void setMinimumWindowSize_enabled_expectedWindowSize() {
final int minimumWindowSize = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
new file mode 100644
index 000000000000..328ad39cddd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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.biometrics
+
+import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
+import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ var mockitoRule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var callback: AuthBiometricView.Callback
+ @Mock
+ private lateinit var panelController: AuthPanelController
+
+ private lateinit var biometricView: AuthBiometricFingerprintAndFaceView
+
+ @Before
+ fun setup() {
+ biometricView = R.layout.auth_biometric_fingerprint_and_face_view
+ .asTestAuthBiometricView(mContext, callback, panelController)
+ waitForIdleSync()
+ }
+
+ @After
+ fun tearDown() {
+ biometricView.destroyDialog()
+ }
+
+ @Test
+ fun fingerprintSuccessDoesNotRequireExplicitConfirmation() {
+ biometricView.onDialogAnimatedIn()
+ biometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT)
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticated).isTrue()
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
+ }
+
+ @Test
+ fun faceSuccessRequiresExplicitConfirmation() {
+ biometricView.onDialogAnimatedIn()
+ biometricView.onAuthenticationSucceeded(TYPE_FACE)
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticated).isFalse()
+ assertThat(biometricView.isAuthenticating).isFalse()
+ assertThat(biometricView.mConfirmButton.visibility).isEqualTo(View.GONE)
+ verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
+
+ // icon acts as confirm button
+ biometricView.mIconView.performClick()
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticated).isTrue()
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
+ }
+
+ @Test
+ fun ignoresFaceErrors() {
+ biometricView.onDialogAnimatedIn()
+ biometricView.onError(TYPE_FACE, "not a face")
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticating).isTrue()
+ verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+
+ biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+ }
+
+ override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
new file mode 100644
index 000000000000..687cb517b2f4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2022 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.biometrics
+
+import android.hardware.biometrics.BiometricAuthenticator
+import android.os.Bundle
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class AuthBiometricFingerprintViewTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ val mockitoRule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var callback: AuthBiometricView.Callback
+ @Mock
+ private lateinit var panelController: AuthPanelController
+
+ private lateinit var biometricView: AuthBiometricView
+
+ private fun createView(allowDeviceCredential: Boolean = false): AuthBiometricFingerprintView {
+ val view = R.layout.auth_biometric_fingerprint_view.asTestAuthBiometricView(
+ mContext, callback, panelController, allowDeviceCredential = allowDeviceCredential
+ ) as AuthBiometricFingerprintView
+ waitForIdleSync()
+ return view
+ }
+
+ @Before
+ fun setup() {
+ biometricView = createView()
+ }
+
+ @After
+ fun tearDown() {
+ biometricView.destroyDialog()
+ }
+
+ @Test
+ fun testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() {
+ biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticated).isTrue()
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
+ }
+
+ @Test
+ fun testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() {
+ biometricView.setRequireConfirmation(true)
+ biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
+ waitForIdleSync()
+
+ // TODO: this should be tested in the subclasses
+ if (biometricView.supportsRequireConfirmation()) {
+ verify(callback, never()).onAction(ArgumentMatchers.anyInt())
+ assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
+ assertThat(biometricView.mCancelButton.visibility).isEqualTo(View.VISIBLE)
+ assertThat(biometricView.mCancelButton.isEnabled).isTrue()
+ assertThat(biometricView.mConfirmButton.isEnabled).isTrue()
+ assertThat(biometricView.mIndicatorView.text)
+ .isEqualTo(mContext.getText(R.string.biometric_dialog_tap_confirm))
+ assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
+ } else {
+ assertThat(biometricView.isAuthenticated).isTrue()
+ verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_AUTHENTICATED))
+ }
+ }
+
+ @Test
+ fun testPositiveButton_sendsActionAuthenticated() {
+ biometricView.mConfirmButton.performClick()
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
+ assertThat(biometricView.isAuthenticated).isTrue()
+ }
+
+ @Test
+ fun testNegativeButton_beforeAuthentication_sendsActionButtonNegative() {
+ biometricView.onDialogAnimatedIn()
+ biometricView.mNegativeButton.performClick()
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE)
+ }
+
+ @Test
+ fun testCancelButton_whenPendingConfirmation_sendsActionUserCanceled() {
+ biometricView.setRequireConfirmation(true)
+ biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
+
+ assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
+ biometricView.mCancelButton.performClick()
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED)
+ }
+
+ @Test
+ fun testTryAgainButton_sendsActionTryAgain() {
+ biometricView.mTryAgainButton.performClick()
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN)
+ assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
+ assertThat(biometricView.isAuthenticating).isTrue()
+ }
+
+ @Test
+ fun testOnErrorSendsActionError() {
+ biometricView.onError(BiometricAuthenticator.TYPE_FACE, "testError")
+ waitForIdleSync()
+
+ verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
+ }
+
+ @Test
+ fun testOnErrorShowsMessage() {
+ // prevent error state from instantly returning to authenticating in the test
+ biometricView.mAnimationDurationHideDialog = 10_000
+
+ val message = "another error"
+ biometricView.onError(BiometricAuthenticator.TYPE_FACE, message)
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticating).isFalse()
+ assertThat(biometricView.isAuthenticated).isFalse()
+ assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
+ assertThat(biometricView.mIndicatorView.text).isEqualTo(message)
+ }
+
+ @Test
+ fun testBackgroundClicked_sendsActionUserCanceled() {
+ val view = View(mContext)
+ biometricView.setBackgroundView(view)
+ view.performClick()
+
+ verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
+ }
+
+ @Test
+ fun testBackgroundClicked_afterAuthenticated_neverSendsUserCanceled() {
+ val view = View(mContext)
+ biometricView.setBackgroundView(view)
+ biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
+ view.performClick()
+
+ verify(callback, never())
+ .onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
+ }
+
+ @Test
+ fun testBackgroundClicked_whenSmallDialog_neverSendsUserCanceled() {
+ biometricView.mLayoutParams = AuthDialog.LayoutParams(0, 0)
+ biometricView.updateSize(AuthDialog.SIZE_SMALL)
+ val view = View(mContext)
+ biometricView.setBackgroundView(view)
+ view.performClick()
+
+ verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
+ }
+
+ @Test
+ fun testIgnoresUselessHelp() {
+ biometricView.mAnimationDurationHideDialog = 10_000
+ biometricView.onDialogAnimatedIn()
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticating).isTrue()
+
+ val helpText = biometricView.mIndicatorView.text
+ biometricView.onHelp(BiometricAuthenticator.TYPE_FINGERPRINT, "")
+ waitForIdleSync()
+
+ // text should not change
+ assertThat(biometricView.mIndicatorView.text).isEqualTo(helpText)
+ verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
+ }
+
+ @Test
+ fun testRestoresState() {
+ val requireConfirmation = true
+ biometricView.mAnimationDurationHideDialog = 10_000
+ val failureMessage = "testFailureMessage"
+ biometricView.setRequireConfirmation(requireConfirmation)
+ biometricView.onAuthenticationFailed(BiometricAuthenticator.TYPE_FACE, failureMessage)
+ waitForIdleSync()
+
+ val state = Bundle()
+ biometricView.onSaveState(state)
+ assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
+ assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY))
+ .isEqualTo(View.GONE)
+ assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_STATE))
+ .isEqualTo(AuthBiometricView.STATE_ERROR)
+ assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
+ assertThat(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)).isTrue()
+ assertThat(biometricView.mIndicatorView.text).isEqualTo(failureMessage)
+ assertThat(state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING))
+ .isEqualTo(failureMessage)
+
+ // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle
+
+ // Create new dialog and restore the previous state into it
+ biometricView.destroyDialog()
+ biometricView = createView()
+ biometricView.restoreState(state)
+ biometricView.mAnimationDurationHideDialog = 10_000
+ biometricView.setRequireConfirmation(requireConfirmation)
+ waitForIdleSync()
+
+ assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
+ assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
+
+ // TODO: Test restored text. Currently cannot test this, since it gets restored only after
+ // dialog size is known.
+ }
+
+ @Test
+ fun testCredentialButton_whenDeviceCredentialAllowed() {
+ biometricView.destroyDialog()
+ biometricView = createView(allowDeviceCredential = true)
+
+ assertThat(biometricView.mUseCredentialButton.visibility).isEqualTo(View.VISIBLE)
+ assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
+
+ biometricView.mUseCredentialButton.performClick()
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL)
+ }
+
+ override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
deleted file mode 100644
index f99b20d47ab8..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-import static android.hardware.biometrics.BiometricManager.Authenticators;
-
-import static com.android.systemui.biometrics.AuthBiometricView.Callback.ACTION_AUTHENTICATED;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.hardware.biometrics.PromptInfo;
-import android.os.Bundle;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.testing.ViewUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.After;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class AuthBiometricViewTest extends SysuiTestCase {
-
- @Rule
- public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- @Mock
- private AuthBiometricView.Callback mCallback;
- @Mock
- private AuthPanelController mPanelController;
-
- private AuthBiometricView mBiometricView;
-
- @After
- public void tearDown() {
- destroyDialog();
- }
-
- @Test
- public void testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- // The onAuthenticated runnable is posted when authentication succeeds.
- mBiometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT);
- waitForIdleSync();
- assertEquals(AuthBiometricView.STATE_AUTHENTICATED, mBiometricView.mState);
- verify(mCallback).onAction(ACTION_AUTHENTICATED);
- }
-
- @Test
- public void testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.setRequireConfirmation(true);
- mBiometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT);
- waitForIdleSync();
-
- // TODO: this should be tested in the subclasses
- if (mBiometricView.supportsRequireConfirmation()) {
- assertEquals(AuthBiometricView.STATE_PENDING_CONFIRMATION, mBiometricView.mState);
-
- verify(mCallback, never()).onAction(anyInt());
-
- assertEquals(View.GONE, mBiometricView.mNegativeButton.getVisibility());
- assertEquals(View.VISIBLE, mBiometricView.mCancelButton.getVisibility());
- assertTrue(mBiometricView.mCancelButton.isEnabled());
-
- assertTrue(mBiometricView.mConfirmButton.isEnabled());
- assertEquals(mContext.getText(R.string.biometric_dialog_tap_confirm),
- mBiometricView.mIndicatorView.getText());
- assertEquals(View.VISIBLE, mBiometricView.mIndicatorView.getVisibility());
- } else {
- assertEquals(AuthBiometricView.STATE_AUTHENTICATED, mBiometricView.mState);
- verify(mCallback).onAction(eq(ACTION_AUTHENTICATED));
- }
-
- }
-
- @Test
- public void testPositiveButton_sendsActionAuthenticated() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.mConfirmButton.performClick();
- waitForIdleSync();
-
- verify(mCallback).onAction(ACTION_AUTHENTICATED);
- assertEquals(AuthBiometricView.STATE_AUTHENTICATED, mBiometricView.mState);
- }
-
- @Test
- public void testNegativeButton_beforeAuthentication_sendsActionButtonNegative() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.onDialogAnimatedIn();
- mBiometricView.mNegativeButton.performClick();
- waitForIdleSync();
-
- verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE);
- }
-
- @Test
- public void testCancelButton_whenPendingConfirmation_sendsActionUserCanceled() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.setRequireConfirmation(true);
- mBiometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT);
-
- assertEquals(View.GONE, mBiometricView.mNegativeButton.getVisibility());
-
- mBiometricView.mCancelButton.performClick();
- waitForIdleSync();
-
- verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED);
- }
-
- @Test
- public void testTryAgainButton_sendsActionTryAgain() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.mTryAgainButton.performClick();
- waitForIdleSync();
-
- verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN);
- assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
- }
-
- @Test
- @Ignore("flaky, b/189031816")
- public void testError_sendsActionError() {
- initDialog(false /* allowDeviceCredential */, mCallback);
- final String testError = "testError";
- mBiometricView.onError(TYPE_FACE, testError);
- waitForIdleSync();
-
- verify(mCallback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR));
- assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
- }
-
- @Test
- public void testBackgroundClicked_sendsActionUserCanceled() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- View view = new View(mContext);
- mBiometricView.setBackgroundView(view);
- view.performClick();
- verify(mCallback).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED));
- }
-
- @Test
- public void testBackgroundClicked_afterAuthenticated_neverSendsUserCanceled() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- View view = new View(mContext);
- mBiometricView.setBackgroundView(view);
- mBiometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT);
- view.performClick();
- verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED));
- }
-
- @Test
- public void testBackgroundClicked_whenSmallDialog_neverSendsUserCanceled() {
- initDialog(false /* allowDeviceCredential */, mCallback);
- mBiometricView.mLayoutParams = new AuthDialog.LayoutParams(0, 0);
- mBiometricView.updateSize(AuthDialog.SIZE_SMALL);
-
- View view = new View(mContext);
- mBiometricView.setBackgroundView(view);
- view.performClick();
- verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED));
- }
-
- @Test
- public void testIgnoresUselessHelp() {
- initDialog(false /* allowDeviceCredential */, mCallback);
-
- mBiometricView.onDialogAnimatedIn();
- waitForIdleSync();
-
- assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
-
- mBiometricView.onHelp(TYPE_FINGERPRINT, "");
- waitForIdleSync();
-
- assertEquals("", mBiometricView.mIndicatorView.getText());
- verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR));
- assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
- }
-
- @Test
- public void testRestoresState() {
- final boolean requireConfirmation = true;
-
- initDialog(false /* allowDeviceCredential */, mCallback, null, 10000);
-
- final String failureMessage = "testFailureMessage";
- mBiometricView.setRequireConfirmation(requireConfirmation);
- mBiometricView.onAuthenticationFailed(TYPE_FACE, failureMessage);
- waitForIdleSync();
-
- Bundle state = new Bundle();
- mBiometricView.onSaveState(state);
-
- assertEquals(View.GONE, mBiometricView.mTryAgainButton.getVisibility());
- assertEquals(View.GONE, state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY));
-
- assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState);
- assertEquals(AuthBiometricView.STATE_ERROR, state.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
-
- assertEquals(View.VISIBLE, mBiometricView.mIndicatorView.getVisibility());
- assertTrue(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING));
-
- assertEquals(failureMessage, mBiometricView.mIndicatorView.getText());
- assertEquals(failureMessage, state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING));
-
- // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle
-
- // Create new dialog and restore the previous state into it
- destroyDialog();
- initDialog(false /* allowDeviceCredential */, mCallback, state, 10000);
- mBiometricView.mAnimationDurationHideDialog = 10000;
- mBiometricView.setRequireConfirmation(requireConfirmation);
- waitForIdleSync();
-
- assertEquals(View.GONE, mBiometricView.mTryAgainButton.getVisibility());
- assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState);
- assertEquals(View.VISIBLE, mBiometricView.mIndicatorView.getVisibility());
-
- // TODO: Test restored text. Currently cannot test this, since it gets restored only after
- // dialog size is known.
- }
-
- @Test
- public void testCredentialButton_whenDeviceCredentialAllowed() throws InterruptedException {
- initDialog(true /* allowDeviceCredential */, mCallback);
-
- assertEquals(View.VISIBLE, mBiometricView.mUseCredentialButton.getVisibility());
- assertEquals(View.GONE, mBiometricView.mNegativeButton.getVisibility());
- mBiometricView.mUseCredentialButton.performClick();
- waitForIdleSync();
-
- verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL);
- }
-
- private PromptInfo buildPromptInfo(boolean allowDeviceCredential) {
- PromptInfo promptInfo = new PromptInfo();
- promptInfo.setTitle("Title");
- int authenticators = Authenticators.BIOMETRIC_WEAK;
- if (allowDeviceCredential) {
- authenticators |= Authenticators.DEVICE_CREDENTIAL;
- } else {
- promptInfo.setNegativeButtonText("Negative");
- }
- promptInfo.setAuthenticators(authenticators);
- return promptInfo;
- }
-
- private void initDialog(boolean allowDeviceCredential, AuthBiometricView.Callback callback) {
- initDialog(allowDeviceCredential, callback,
- null /* savedState */, 0 /* hideDelay */);
- }
-
- private void initDialog(boolean allowDeviceCredential,
- AuthBiometricView.Callback callback, Bundle savedState, int hideDelay) {
- final LayoutInflater inflater = LayoutInflater.from(mContext);
- mBiometricView = (AuthBiometricView) inflater.inflate(
- R.layout.auth_biometric_view, null, false);
- mBiometricView.mAnimationDurationLong = 0;
- mBiometricView.mAnimationDurationShort = 0;
- mBiometricView.mAnimationDurationHideDialog = hideDelay;
- mBiometricView.setPromptInfo(buildPromptInfo(allowDeviceCredential));
- mBiometricView.setCallback(callback);
- mBiometricView.restoreState(savedState);
- ViewUtils.attachView(mBiometricView);
- mBiometricView.setPanelController(mPanelController);
- waitForIdleSync();
- }
-
- private void destroyDialog() {
- if (mBiometricView != null && mBiometricView.isAttachedToWindow()) {
- ViewUtils.detachView(mBiometricView);
- }
- }
-
- @Override
- protected void waitForIdleSync() {
- TestableLooper.get(this).processAllMessages();
- super.waitForIdleSync();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 2341928b2565..31fe39a2a170 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -16,13 +16,11 @@
package com.android.systemui.biometrics
import android.app.admin.DevicePolicyManager
+import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricManager
-import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.PromptInfo
-import android.hardware.biometrics.SensorProperties
import android.hardware.face.FaceSensorPropertiesInternal
-import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.os.Handler
import android.os.IBinder
@@ -36,11 +34,11 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.widget.ScrollView
import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -57,12 +55,12 @@ import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
class AuthContainerViewTest : SysuiTestCase() {
@JvmField @Rule
- var rule = MockitoJUnit.rule()
+ var mockitoRule = MockitoJUnit.rule()
@Mock
lateinit var callback: AuthDialogCallback
@@ -74,6 +72,8 @@ class AuthContainerViewTest : SysuiTestCase() {
lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock
lateinit var windowToken: IBinder
+ @Mock
+ lateinit var interactionJankMonitor: InteractionJankMonitor
private var authContainer: TestAuthContainerView? = null
@@ -86,13 +86,13 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testNotifiesAnimatedIn() {
- initializeContainer()
+ initializeFingerprintContainer()
verify(callback).onDialogAnimatedIn()
}
@Test
fun testIgnoresAnimatedInWhenDismissed() {
- val container = initializeContainer(addToView = false)
+ val container = initializeFingerprintContainer(addToView = false)
container.dismissFromSystemServer()
waitForIdleSync()
@@ -107,7 +107,7 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
- val container = initializeContainer()
+ val container = initializeFingerprintContainer()
container.mBiometricCallback.onAction(
AuthBiometricView.Callback.ACTION_AUTHENTICATED
)
@@ -122,7 +122,7 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionUserCanceled_sendsDismissedUserCanceled() {
- val container = initializeContainer()
+ val container = initializeFingerprintContainer()
container.mBiometricCallback.onAction(
AuthBiometricView.Callback.ACTION_USER_CANCELED
)
@@ -140,7 +140,7 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionButtonNegative_sendsDismissedButtonNegative() {
- val container = initializeContainer()
+ val container = initializeFingerprintContainer()
container.mBiometricCallback.onAction(
AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE
)
@@ -155,7 +155,9 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionTryAgain_sendsTryAgain() {
- val container = initializeContainer(BiometricManager.Authenticators.BIOMETRIC_WEAK)
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ )
container.mBiometricCallback.onAction(
AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN
)
@@ -166,8 +168,8 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionError_sendsDismissedError() {
- val container = initializeContainer()
- authContainer!!.mBiometricCallback.onAction(
+ val container = initializeFingerprintContainer()
+ container.mBiometricCallback.onAction(
AuthBiometricView.Callback.ACTION_ERROR
)
waitForIdleSync()
@@ -181,8 +183,8 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
- val container = initializeContainer(
- BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
container.mBiometricCallback.onAction(
@@ -196,8 +198,8 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testAnimateToCredentialUI_invokesStartTransitionToCredentialUI() {
- val container = initializeContainer(
- BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
container.animateToCredentialUI()
@@ -208,7 +210,7 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testShowBiometricUI() {
- val container = initializeContainer()
+ val container = initializeFingerprintContainer()
waitForIdleSync()
@@ -218,7 +220,9 @@ class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testShowCredentialUI() {
- val container = initializeContainer(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -232,7 +236,9 @@ class AuthContainerViewTest : SysuiTestCase() {
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
)
- val container = initializeContainer(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialPatternView()).isTrue()
@@ -249,7 +255,9 @@ class AuthContainerViewTest : SysuiTestCase() {
// In the credential view, clicking on the background (to cancel authentication) is not
// valid. Thus, the listener should be null, and it should not be in the accessibility
// hierarchy.
- val container = initializeContainer(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialPasswordView()).isTrue()
@@ -277,49 +285,52 @@ class AuthContainerViewTest : SysuiTestCase() {
assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.ime()) == 0).isTrue()
}
- private fun initializeContainer(
+ @Test
+ fun coexFaceRestartsOnTouch() {
+ val container = initializeCoexContainer()
+
+ container.onPointerDown()
+ waitForIdleSync()
+
+ container.onAuthenticationFailed(BiometricAuthenticator.TYPE_FACE, "failed")
+ waitForIdleSync()
+
+ verify(callback, never()).onTryAgainPressed()
+
+ container.onPointerDown()
+ waitForIdleSync()
+
+ verify(callback).onTryAgainPressed()
+ }
+
+ private fun initializeFingerprintContainer(
+ authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
+ addToView: Boolean = true
+ ) = initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal()
+ ),
+ addToView
+ )
+
+ private fun initializeCoexContainer(
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
addToView: Boolean = true
+ ) = initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal(),
+ faceProps = faceSensorPropertiesInternal()
+ ),
+ addToView
+ )
+
+ private fun initializeContainer(
+ view: TestAuthContainerView,
+ addToView: Boolean
): TestAuthContainerView {
- val config = AuthContainerView.Config()
- config.mContext = mContext
- config.mCallback = callback
- config.mSensorIds = intArrayOf(0)
- config.mSkipAnimation = true
- config.mPromptInfo = PromptInfo()
- config.mPromptInfo.authenticators = authenticators
- val componentInfo = listOf(
- ComponentInfoInternal(
- "faceSensor" /* componentId */,
- "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
- "00000001" /* serialNumber */, "" /* softwareVersion */
- ),
- ComponentInfoInternal(
- "matchingAlgorithm" /* componentId */,
- "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
- "vendor/version/revision" /* softwareVersion */
- )
- )
- val fpProps = listOf(
- FingerprintSensorPropertiesInternal(
- 0,
- SensorProperties.STRENGTH_STRONG,
- 5 /* maxEnrollmentsPerUser */,
- componentInfo,
- FingerprintSensorProperties.TYPE_REAR,
- false /* resetLockoutRequiresHardwareAuthToken */
- )
- )
- authContainer = TestAuthContainerView(
- config,
- fpProps,
- listOf(),
- wakefulnessLifecycle,
- userManager,
- lockPatternUtils,
- Handler(TestableLooper.get(this).looper),
- FakeExecutor(FakeSystemClock())
- )
+ authContainer = view
if (addToView) {
authContainer!!.addToView()
@@ -329,27 +340,35 @@ class AuthContainerViewTest : SysuiTestCase() {
}
private inner class TestAuthContainerView(
- config: Config,
- fpProps: List<FingerprintSensorPropertiesInternal>,
- faceProps: List<FaceSensorPropertiesInternal>,
- wakefulnessLifecycle: WakefulnessLifecycle,
- userManager: UserManager,
- lockPatternUtils: LockPatternUtils,
- mainHandler: Handler,
- bgExecutor: DelayableExecutor
+ authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
+ fingerprintProps: List<FingerprintSensorPropertiesInternal> = listOf(),
+ faceProps: List<FaceSensorPropertiesInternal> = listOf()
) : AuthContainerView(
- config, fpProps, faceProps,
- wakefulnessLifecycle, userManager, lockPatternUtils, mainHandler, bgExecutor
+ Config().apply {
+ mContext = this@AuthContainerViewTest.context
+ mCallback = callback
+ mSensorIds = (fingerprintProps.map { it.sensorId } +
+ faceProps.map { it.sensorId }).toIntArray()
+ mSkipAnimation = true
+ mPromptInfo = PromptInfo().apply {
+ this.authenticators = authenticators
+ }
+ },
+ fingerprintProps,
+ faceProps,
+ wakefulnessLifecycle,
+ userManager,
+ lockPatternUtils,
+ interactionJankMonitor,
+ Handler(TestableLooper.get(this).looper),
+ FakeExecutor(FakeSystemClock())
) {
override fun postOnAnimation(runnable: Runnable) {
runnable.run()
}
}
- override fun waitForIdleSync() {
- TestableLooper.get(this).processAllMessages()
- super.waitForIdleSync()
- }
+ override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
private fun AuthContainerView.addToView() {
ViewUtils.attachView(this)
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 eefc412e3ffa..d948a99f8ad8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -77,6 +77,7 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -150,6 +151,8 @@ public class AuthControllerTest extends SysuiTestCase {
private LockPatternUtils mLockPatternUtils;
@Mock
private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private InteractionJankMonitor mInteractionJankMonitor;
@Captor
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
@Captor
@@ -788,8 +791,8 @@ public class AuthControllerTest extends SysuiTestCase {
super(context, execution, commandQueue, activityTaskManager, windowManager,
fingerprintManager, faceManager, udfpsControllerFactory,
sidefpsControllerFactory, mDisplayManager, mWakefulnessLifecycle,
- mUserManager, mLockPatternUtils, statusBarStateController, mHandler,
- mBackgroundExecutor);
+ mUserManager, mLockPatternUtils, statusBarStateController,
+ mInteractionJankMonitor, mHandler, mBackgroundExecutor);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 7f8656c1ecbc..d6afd6d192ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -292,7 +292,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Test
@RunWithLooper(setAsMainLooper = true)
- fun testAnimatorRunWhenWakeAndUnlock() {
+ fun testAnimatorRunWhenWakeAndUnlock_fingerprint() {
val fpsLocation = PointF(5f, 5f)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
@@ -309,6 +309,25 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
+ @RunWithLooper(setAsMainLooper = true)
+ fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() {
+ val faceLocation = PointF(5f, 5f)
+ `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
+ `when`(authController.isUdfpsFingerDown).thenReturn(true)
+
+ controller.showUnlockRipple(BiometricSourceType.FACE)
+ assertTrue("reveal didn't start on keyguardFadingAway",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
+ `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
+ controller.onKeyguardFadingAwayChanged()
+ assertFalse("reveal triggers multiple times",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
+ }
+
+ @Test
fun testUpdateRippleColor() {
controller.onViewAttached()
val captor = ArgumentCaptor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
index 92c2a1b9b23a..8820c164cba4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -16,29 +16,123 @@
package com.android.systemui.biometrics
+import android.annotation.IdRes
+import android.content.Context
+import android.hardware.biometrics.BiometricManager
import android.hardware.biometrics.ComponentInfoInternal
-import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.SensorProperties
+import android.hardware.face.FaceSensorPropertiesInternal
+import android.hardware.face.FaceSensorProperties
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.os.Bundle
-/** Creates properties from the sensor location with test values. */
-fun SensorLocationInternal.asFingerprintSensorProperties(
- sensorId: Int = 22,
- @SensorProperties.Strength sensorStrength: Int = SensorProperties.STRENGTH_WEAK,
- @FingerprintSensorProperties.SensorType sensorType: Int =
- FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
- maxEnrollmentsPerUser: Int = 1,
- halControlsIllumination: Boolean = true,
- info: List<ComponentInfoInternal> = listOf(ComponentInfoInternal("a", "b", "c", "d", "e")),
- resetLockoutRequiresHardwareAuthToken: Boolean = false
-) = FingerprintSensorPropertiesInternal(
- sensorId,
- sensorStrength,
- maxEnrollmentsPerUser,
- info,
- sensorType,
- halControlsIllumination,
- resetLockoutRequiresHardwareAuthToken,
- listOf(this)
-)
+import android.testing.ViewUtils
+import android.view.LayoutInflater
+
+/**
+ * Inflate the given BiometricPrompt layout and initialize it with test parameters.
+ *
+ * This attaches the view so be sure to call [destroyDialog] at the end of the test.
+ */
+@IdRes
+internal fun <T : AuthBiometricView> Int.asTestAuthBiometricView(
+ context: Context,
+ callback: AuthBiometricView.Callback,
+ panelController: AuthPanelController,
+ allowDeviceCredential: Boolean = false,
+ savedState: Bundle? = null,
+ hideDelay: Int = 0
+): T {
+ val view = LayoutInflater.from(context).inflate(this, null, false) as T
+ view.mAnimationDurationLong = 0
+ view.mAnimationDurationShort = 0
+ view.mAnimationDurationHideDialog = hideDelay
+ view.setPromptInfo(buildPromptInfo(allowDeviceCredential))
+ view.setCallback(callback)
+ view.restoreState(savedState)
+ view.setPanelController(panelController)
+
+ ViewUtils.attachView(view)
+
+ return view
+}
+
+private fun buildPromptInfo(allowDeviceCredential: Boolean): PromptInfo {
+ val promptInfo = PromptInfo()
+ promptInfo.title = "Title"
+ var authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ if (allowDeviceCredential) {
+ authenticators = authenticators or BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ } else {
+ promptInfo.negativeButtonText = "Negative"
+ }
+ promptInfo.authenticators = authenticators
+ return promptInfo
+}
+
+/** Detach the view, if needed. */
+internal fun AuthBiometricView?.destroyDialog() {
+ if (this != null && isAttachedToWindow) {
+ ViewUtils.detachView(this)
+ }
+}
+
+/** Create [FingerprintSensorPropertiesInternal] for a test. */
+internal fun fingerprintSensorPropertiesInternal(
+ ids: List<Int> = listOf(0)
+): List<FingerprintSensorPropertiesInternal> {
+ val componentInfo = listOf(
+ ComponentInfoInternal(
+ "fingerprintSensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+ "00000001" /* serialNumber */, "" /* softwareVersion */
+ ),
+ ComponentInfoInternal(
+ "matchingAlgorithm" /* componentId */,
+ "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+ "vendor/version/revision" /* softwareVersion */
+ )
+ )
+ return ids.map { id ->
+ FingerprintSensorPropertiesInternal(
+ id,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ componentInfo,
+ FingerprintSensorProperties.TYPE_REAR,
+ false /* resetLockoutRequiresHardwareAuthToken */
+ )
+ }
+}
+
+/** Create [FaceSensorPropertiesInternal] for a test. */
+internal fun faceSensorPropertiesInternal(
+ ids: List<Int> = listOf(1)
+): List<FaceSensorPropertiesInternal> {
+ val componentInfo = listOf(
+ ComponentInfoInternal(
+ "faceSensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+ "00000001" /* serialNumber */, "" /* softwareVersion */
+ ),
+ ComponentInfoInternal(
+ "matchingAlgorithm" /* componentId */,
+ "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+ "vendor/version/revision" /* softwareVersion */
+ )
+ )
+ return ids.map { id ->
+ FaceSensorPropertiesInternal(
+ id,
+ SensorProperties.STRENGTH_STRONG,
+ 2 /* maxEnrollmentsPerUser */,
+ componentInfo,
+ FaceSensorProperties.TYPE_RGB,
+ true /* supportsFaceDetection */,
+ true /* supportsSelfIllumination */,
+ false /* resetLockoutRequiresHardwareAuthToken */
+ )
+ }
+}
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 e7e8e73c3bc1..554e27dde5ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -590,6 +590,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
@@ -607,6 +608,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
mBiometricsExecutor.runAllReady();
moveEvent.recycle();
+ mFgExecutor.runAllReady();
// THEN FingerprintManager is notified about onPointerDown
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(0f),
eq(0f));
@@ -616,6 +618,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
+ verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
mBiometricsExecutor.runAllReady();
@@ -634,6 +637,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
// WHEN fingerprint is requested because of AOD interrupt
mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
+ mFgExecutor.runAllReady();
// THEN illumination begins
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -643,6 +647,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
anyFloat(), anyFloat());
+ verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
}
@Test
@@ -670,6 +675,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor.runAllReady();
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
+ mFgExecutor.runAllReady();
when(mUdfpsView.isIlluminationRequested()).thenReturn(true);
// WHEN it times out
mFgExecutor.advanceClockToNext();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
index cd646c665d03..78fb5b00a21e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
@@ -70,7 +70,7 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
assertEquals(970,
UdfpsDialogMeasureAdapter.calculateBottomSpacerHeightForPortrait(
props, displayHeightPx, textIndicatorHeightPx, buttonBarHeightPx,
- dialogBottomMarginPx, navbarHeightPx
+ dialogBottomMarginPx, navbarHeightPx, 1.0f /* resolutionScale */
));
}
@@ -135,6 +135,7 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
assertEquals(1205,
UdfpsDialogMeasureAdapter.calculateHorizontalSpacerWidthForLandscape(
- props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx));
+ props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx,
+ 1.0f /* resolutionScale */));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
new file mode 100644
index 000000000000..a61cecbabf30
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import androidx.test.filters.SmallTest;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BroadcastDialogTest extends SysuiTestCase {
+
+ private static final String SWITCH_APP = "Music";
+ private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files";
+ private BroadcastDialog mBroadcastDialog;
+ private View mDialogView;
+ private TextView mSubTitle;
+ private Button mChangeOutputButton;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class),
+ SWITCH_APP, TEST_PACKAGE, mock(UiEventLogger.class));
+ mBroadcastDialog.show();
+ mDialogView = mBroadcastDialog.mDialogView;
+ }
+
+ @After
+ public void tearDown() {
+ mBroadcastDialog.dismiss();
+ }
+
+ @Test
+ public void onCreate_withCurrentApp_checkSwitchAppContent() {
+ mSubTitle = mDialogView.requireViewById(R.id.dialog_subtitle);
+
+ assertThat(mSubTitle.getText()).isEqualTo(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, SWITCH_APP));
+ }
+
+ @Test
+ public void onClick_withChangeOutput_dismissBroadcastDialog() {
+ mChangeOutputButton = mDialogView.requireViewById(R.id.change_output);
+ mChangeOutputButton.performClick();
+
+ assertThat(mBroadcastDialog.isShowing()).isFalse();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
index b7de6c15459c..25d4c472dc63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -48,6 +49,8 @@ public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
@Mock
StatusBarNotification mNotification2;
@Mock
+ StatusBarNotification mNotification3;
+ @Mock
NotificationListenerService.RankingMap mRankingMap;
private DreamOverlayNotificationCountProvider mProvider;
@@ -58,6 +61,8 @@ public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
when(mNotification1.getKey()).thenReturn("key1");
when(mNotification2.getKey()).thenReturn("key2");
+ when(mNotification3.getKey()).thenReturn("key3");
+ when(mNotification3.isOngoing()).thenReturn(true);
final StatusBarNotification[] notifications = {mNotification1};
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
@@ -83,4 +88,13 @@ public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
handlerArgumentCaptor.getValue().onNotificationRemoved(mNotification1, mRankingMap);
verify(mCallback).onNotificationCountChanged(0);
}
+
+ @Test
+ public void testPostingOngoingNotificationDoesNotCallCallbackWithNotificationCount() {
+ final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor =
+ ArgumentCaptor.forClass(NotificationHandler.class);
+ verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture());
+ handlerArgumentCaptor.getValue().onNotificationPosted(mNotification3, mRankingMap);
+ verify(mCallback, never()).onNotificationCountChanged(2);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
index ed1cf69ad8c0..cefdf283fc7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
@@ -27,7 +27,7 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dreams.smartspace.DreamsSmartspaceController;
+import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import org.junit.Before;
@@ -47,7 +47,7 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
private Context mContext;
@Mock
- private DreamsSmartspaceController mSmartspaceController;
+ private DreamSmartspaceController mSmartspaceController;
@Mock
private DreamOverlayStateController mDreamOverlayStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 89c82fbff901..c3fca29a9883 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -422,7 +422,29 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
verify(mUiEventLogger).log(BouncerSwipeTouchHandler.DreamEvent.DREAM_BOUNCER_FULLY_VISIBLE);
}
+ /**
+ * Ensures {@link CentralSurfaces}
+ */
+ @Test
+ public void testInformBouncerShowingOnExpand() {
+ swipeToPosition(1f, Direction.UP, 0);
+ }
+
+ /**
+ * Ensures {@link CentralSurfaces}
+ */
+ @Test
+ public void testInformBouncerHidingOnCollapse() {
+ // Must swipe up to set initial state.
+ swipeToPosition(1f, Direction.UP, 0);
+ Mockito.clearInvocations(mCentralSurfaces);
+
+ swipeToPosition(0f, Direction.DOWN, 0);
+ }
+
+
private void swipeToPosition(float percent, Direction direction, float velocityY) {
+ Mockito.clearInvocations(mTouchSession);
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
index 0a021331d9d1..14a5702c8e5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
@@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -59,6 +60,9 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {
TouchInsetManager mTouchInsetManager;
@Mock
+ StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+ @Mock
Handler mHandler;
@Mock
@@ -83,12 +87,45 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {
mVisibilityController,
RESTORE_TIMEOUT,
mTouchInsetManager,
+ mStatusBarKeyguardViewManager,
mFakeExecutor,
mHandler);
// Report multiple active sessions.
when(mSession.getActiveSessionCount()).thenReturn(2);
+ // Bouncer hidden.
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+
+ // Start session.
+ touchHandler.onSessionStart(mSession);
+
+ // Verify session end.
+ verify(mSession).pop();
+
+ // Verify no interaction with visibility controller.
+ verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ }
+
+ /**
+ * Ensures no actions are taken when the bouncer is showing.
+ */
+ @Test
+ public void testSessionEndWhenBouncerShowing() {
+ final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
+ mVisibilityController,
+ RESTORE_TIMEOUT,
+ mTouchInsetManager,
+ mStatusBarKeyguardViewManager,
+ mFakeExecutor,
+ mHandler);
+
+ // Report one session.
+ when(mSession.getActiveSessionCount()).thenReturn(1);
+
+ // Bouncer is showing.
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+
// Start session.
touchHandler.onSessionStart(mSession);
@@ -108,12 +145,16 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {
mVisibilityController,
RESTORE_TIMEOUT,
mTouchInsetManager,
+ mStatusBarKeyguardViewManager,
mFakeExecutor,
mHandler);
// Report one session
when(mSession.getActiveSessionCount()).thenReturn(1);
+ // Bouncer hidden.
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+
// Start session
touchHandler.onSessionStart(mSession);
@@ -149,12 +190,16 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {
mVisibilityController,
RESTORE_TIMEOUT,
mTouchInsetManager,
+ mStatusBarKeyguardViewManager,
mFakeExecutor,
mHandler);
// Report one session
when(mSession.getActiveSessionCount()).thenReturn(1);
+ // Bouncer hidden.
+ when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+
// Start session
touchHandler.onSessionStart(mSession);
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 241ed2443e6c..540f2a534854 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -58,6 +58,7 @@ import com.android.internal.logging.InstanceId
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.MediaControlPanel.KEY_SMARTSPACE_APP_NAME
import com.android.systemui.media.dialog.MediaOutputDialogFactory
@@ -104,6 +105,7 @@ private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME"
private const val REC_APP_NAME = "REC APP NAME"
+private const val APP_NAME = "APP_NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -130,6 +132,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var transitionParent: ViewGroup
+ @Mock private lateinit var broadcastDialogController: BroadcastDialogController
private lateinit var appIcon: ImageView
@Mock private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -160,8 +163,9 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var dismissText: TextView
private lateinit var session: MediaSession
- private val device = MediaDeviceData(true, null, DEVICE_NAME)
- private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME)
+ private lateinit var device: MediaDeviceData
+ private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME, null,
+ showBroadcastButton = false)
private lateinit var mediaData: MediaData
private val clock = FakeSystemClock()
@Mock private lateinit var logger: MediaUiEventLogger
@@ -187,6 +191,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var recSubtitle1: TextView
private lateinit var recSubtitle2: TextView
private lateinit var recSubtitle3: TextView
+ private var shouldShowBroadcastButton: Boolean = false
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -223,7 +228,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
logger,
keyguardStateController,
activityIntentHelper,
- lockscreenUserManager) {
+ lockscreenUserManager,
+ broadcastDialogController) {
override fun loadAnimator(
animId: Int,
otionInterpolator: Interpolator,
@@ -236,28 +242,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
initGutsViewHolderMocks()
initMediaViewHolderMocks()
- // Create media session
- val metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
- val playbackBuilder = PlaybackState.Builder().apply {
- setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- setActions(PlaybackState.ACTION_PLAY)
- }
- session = MediaSession(context, SESSION_KEY).apply {
- setMetadata(metadataBuilder.build())
- setPlaybackState(playbackBuilder.build())
- }
- session.setActive(true)
-
- mediaData = MediaTestUtils.emptyMediaData.copy(
- artist = ARTIST,
- song = TITLE,
- packageName = PACKAGE,
- token = session.sessionToken,
- device = device,
- instanceId = instanceId)
+ initDeviceMediaData(false, DEVICE_NAME)
// Set up recommendation view
initRecommendationViewHolderMocks()
@@ -293,6 +278,34 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(gutsViewHolder.dismissText).thenReturn(dismissText)
}
+ private fun initDeviceMediaData(shouldShowBroadcastButton: Boolean, name: String) {
+ device = MediaDeviceData(true, null, name, null,
+ showBroadcastButton = shouldShowBroadcastButton)
+
+ // Create media session
+ val metadataBuilder = MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ val playbackBuilder = PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session = MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
+ session.setActive(true)
+
+ mediaData = MediaTestUtils.emptyMediaData.copy(
+ artist = ARTIST,
+ song = TITLE,
+ packageName = PACKAGE,
+ token = session.sessionToken,
+ device = device,
+ instanceId = instanceId)
+ }
+
/**
* Initialize elements in media view holder
*/
@@ -1032,6 +1045,28 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(seamless.isEnabled()).isFalse()
}
+ @Test
+ fun bindBroadcastButton() {
+ initMediaViewHolderMocks()
+ initDeviceMediaData(true, APP_NAME)
+
+ val mockAvd0 = mock(AnimatedVectorDrawable::class.java)
+ whenever(mockAvd0.mutate()).thenReturn(mockAvd0)
+ val semanticActions0 = MediaButton(
+ playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)
+ )
+ val state = mediaData.copy(resumption = true, semanticActions = semanticActions0,
+ isPlaying = false)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+ assertThat(seamlessText.getText()).isEqualTo(APP_NAME)
+ assertThat(seamless.isEnabled()).isTrue()
+
+ seamless.callOnClick()
+
+ verify(logger).logOpenBroadcastDialog(anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
/* ***** Guts tests for the player ***** */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 3e335c5163a9..04b93d79f83b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -79,7 +79,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L,
InstanceId.fakeInstanceId(-1), -1);
- mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
+ mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME, null, false);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index 18ee79138b52..11fe87d363a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -16,6 +16,10 @@
package com.android.systemui.media
+import android.bluetooth.BluetoothLeBroadcast
+import android.bluetooth.BluetoothLeBroadcastMetadata
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
@@ -25,8 +29,12 @@ import android.media.session.MediaSession
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
@@ -42,6 +50,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.mock
@@ -57,6 +66,8 @@ private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val REMOTE_DEVICE_NAME = "REMOTE_DEVICE_NAME"
+private const val BROADCAST_APP_NAME = "BROADCAST_APP_NAME"
+private const val NORMAL_APP_NAME = "NORMAL_APP_NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -80,6 +91,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Mock private lateinit var controller: MediaController
@Mock private lateinit var playbackInfo: PlaybackInfo
@Mock private lateinit var configurationController: ConfigurationController
+ @Mock private lateinit var bluetoothLeBroadcast: BluetoothLeBroadcast
+ @Mock private lateinit var localBluetoothProfileManager: LocalBluetoothProfileManager
+ @Mock private lateinit var localBluetoothLeBroadcast: LocalBluetoothLeBroadcast
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var applicationInfo: ApplicationInfo
+ private lateinit var localBluetoothManager: LocalBluetoothManager
private lateinit var session: MediaSession
private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -88,12 +105,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun setUp() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
fakeBgExecutor = FakeExecutor(FakeSystemClock())
+ localBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager::class.java)
manager = MediaDeviceManager(
+ context,
controllerFactory,
lmmFactory,
mr2,
muteAwaitFactory,
configurationController,
+ localBluetoothManager,
fakeFgExecutor,
fakeBgExecutor,
dumpster
@@ -116,6 +136,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
token = session.sessionToken)
whenever(controllerFactory.create(session.sessionToken))
.thenReturn(controller)
+ setupLeAudioConfiguration(false)
}
@After
@@ -459,7 +480,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun testRemotePlaybackDeviceOverride() {
whenever(route.name).thenReturn(DEVICE_NAME)
- val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null)
+ val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null,
+ showBroadcastButton = false)
val mediaDataWithDevice = mediaData.copy(device = deviceData)
// GIVEN media data that already has a device set
@@ -474,12 +496,95 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
verify(lmm, never()).registerCallback(any())
}
+ @Test
+ fun onBroadcastStarted_currentMediaDeviceDataIsBroadcasting() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(true)
+ setupBroadcastPackage(BROADCAST_APP_NAME)
+ broadcastCallback.onBroadcastStarted(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isTrue()
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(context.getString(
+ R.string.broadcasting_description_is_broadcasting))
+ }
+
+ @Test
+ fun onBroadcastStarted_currentMediaDeviceDataIsNotBroadcasting() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(true)
+ setupBroadcastPackage(NORMAL_APP_NAME)
+ broadcastCallback.onBroadcastStarted(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isTrue()
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(BROADCAST_APP_NAME)
+ }
+
+ @Test
+ fun onBroadcastStopped_bluetoothLeBroadcastIsDisabledAndBroadcastingButtonIsGone() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(false)
+ broadcastCallback.onBroadcastStopped(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isFalse()
+ }
+
fun captureCallback(): LocalMediaManager.DeviceCallback {
val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
verify(lmm).registerCallback(captor.capture())
return captor.getValue()
}
+ fun setupBroadcastCallback(): BluetoothLeBroadcast.Callback {
+ val callback: BluetoothLeBroadcast.Callback = object : BluetoothLeBroadcast.Callback {
+ override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStartFailed(reason: Int) {}
+ override fun onBroadcastStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStopFailed(reason: Int) {}
+ override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
+ override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastMetadataChanged(broadcastId: Int,
+ metadata: BluetoothLeBroadcastMetadata) {}
+ }
+
+ bluetoothLeBroadcast.registerCallback(fakeFgExecutor, callback)
+ return callback;
+ }
+
+ fun setupLeAudioConfiguration(isLeAudio: Boolean) {
+ whenever(localBluetoothManager.profileManager).thenReturn(localBluetoothProfileManager)
+ whenever(localBluetoothProfileManager.leAudioBroadcastProfile)
+ .thenReturn(localBluetoothLeBroadcast)
+ whenever(localBluetoothLeBroadcast.isEnabled(any())).thenReturn(isLeAudio)
+ whenever(localBluetoothLeBroadcast.appSourceName).thenReturn(BROADCAST_APP_NAME)
+ }
+
+ fun setupBroadcastPackage(currentName: String) {
+ whenever(lmm.packageName).thenReturn(PACKAGE)
+ whenever(packageManager.getApplicationInfo(eq(PACKAGE), anyInt()))
+ .thenReturn(applicationInfo)
+ whenever(packageManager.getApplicationLabel(applicationInfo)).thenReturn(currentName)
+ context.setMockPackageManager(packageManager)
+ }
+
fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
index ae58fe67da23..3d9ed5fe7f7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
@@ -20,7 +20,8 @@ class MediaTestUtils {
device = null,
active = true,
resumeAction = null,
+ isPlaying = false,
instanceId = InstanceId.fakeInstanceId(-1),
appUid = -1)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
new file mode 100644
index 000000000000..18178097d5e3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
@@ -0,0 +1,86 @@
+package com.android.systemui.media
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.MeasurementInput
+import com.android.systemui.util.animation.TransitionLayout
+import com.android.systemui.util.animation.TransitionViewState
+import com.android.systemui.util.animation.WidgetState
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+/**
+ * Tests for {@link MediaViewController}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaViewControllerTest : SysuiTestCase() {
+ @Mock
+ private lateinit var logger: MediaViewLogger
+
+ private val configurationController =
+ com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
+ private val mediaHostStatesManager = MediaHostStatesManager()
+ private lateinit var mediaViewController: MediaViewController
+ private val mediaHostStateHolder = MediaHost.MediaHostStateHolder()
+ private var transitionLayout = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
+ @Mock private lateinit var mockViewState: TransitionViewState
+ @Mock private lateinit var mockCopiedState: TransitionViewState
+ @Mock private lateinit var mockWidgetState: WidgetState
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mediaViewController = MediaViewController(
+ context,
+ configurationController,
+ mediaHostStatesManager,
+ logger
+ )
+ mediaViewController.attach(transitionLayout, MediaViewController.TYPE.PLAYER)
+ }
+
+ @Test
+ fun testObtainViewState_applySquishFraction_toTransitionViewState_height() {
+ transitionLayout.measureState = TransitionViewState().apply {
+ this.height = 100
+ }
+ mediaHostStateHolder.expansion = 1f
+ val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ mediaHostStateHolder.measurementInput =
+ MeasurementInput(widthMeasureSpec, heightMeasureSpec)
+
+ // Test no squish
+ mediaHostStateHolder.squishFraction = 1f
+ assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
+
+ // Test half squish
+ mediaHostStateHolder.squishFraction = 0.5f
+ assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
+ }
+
+ @Test
+ fun testSquish_DoesNotMutateViewState() {
+ whenever(mockViewState.copy()).thenReturn(mockCopiedState)
+ whenever(mockCopiedState.widgetStates)
+ .thenReturn(mutableMapOf(R.id.album_art to mockWidgetState))
+
+ mediaViewController.squishViewState(mockViewState, 0.5f)
+ verify(mockViewState, times(1)).copy()
+ verifyNoMoreInteractions(mockViewState)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index 0f2c2647f20f..ca3182affcc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.qs.tiles.ColorInversionTile
import com.android.systemui.qs.tiles.DataSaverTile
import com.android.systemui.qs.tiles.DeviceControlsTile
import com.android.systemui.qs.tiles.DndTile
+import com.android.systemui.qs.tiles.DreamTile
import com.android.systemui.qs.tiles.FlashlightTile
import com.android.systemui.qs.tiles.HotspotTile
import com.android.systemui.qs.tiles.InternetTile
@@ -89,7 +90,8 @@ private val specMap = mapOf(
"wallet" to QuickAccessWalletTile::class.java,
"qr_code_scanner" to QRCodeScannerTile::class.java,
"onehanded" to OneHandedModeTile::class.java,
- "color_correction" to ColorCorrectionTile::class.java
+ "color_correction" to ColorCorrectionTile::class.java,
+ "dream" to DreamTile::class.java
)
@RunWith(AndroidTestingRunner::class)
@@ -129,6 +131,7 @@ class QSFactoryImplTest : SysuiTestCase() {
@Mock private lateinit var qrCodeScannerTile: QRCodeScannerTile
@Mock private lateinit var oneHandedModeTile: OneHandedModeTile
@Mock private lateinit var colorCorrectionTile: ColorCorrectionTile
+ @Mock private lateinit var dreamTile: DreamTile
private lateinit var factory: QSFactoryImpl
@@ -171,7 +174,8 @@ class QSFactoryImplTest : SysuiTestCase() {
{ quickAccessWalletTile },
{ qrCodeScannerTile },
{ oneHandedModeTile },
- { colorCorrectionTile }
+ { colorCorrectionTile },
+ { dreamTile }
)
// When adding/removing tiles, fix also [specMap]
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index cc472481ad8a..d65901777a73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -10,6 +10,7 @@ import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
@@ -18,6 +19,7 @@ import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSTileHost
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.BluetoothController
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -25,6 +27,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -84,6 +87,53 @@ class BluetoothTileTest : SysuiTestCase() {
assertThat(tile.restrictionChecked).isEqualTo(UserManager.DISALLOW_BLUETOOTH)
}
+ @Test
+ fun testIcon_whenDisabled_isOffState() {
+ val state = QSTile.BooleanState()
+ disableBluetooth()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenDisconnected_isOffState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothDisconnected()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenConnected_isOnState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothConnected()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_on))
+ }
+
+ @Test
+ fun testIcon_whenConnecting_isSearchState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothConnecting()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_search))
+ }
+
private class FakeBluetoothTile(
qsTileHost: QSTileHost,
backgroundLooper: Looper,
@@ -114,4 +164,27 @@ class BluetoothTileTest : SysuiTestCase() {
restrictionChecked = userRestriction
}
}
+
+ fun enableBluetooth() {
+ `when`(bluetoothController.isBluetoothEnabled).thenReturn(true)
+ }
+
+ fun disableBluetooth() {
+ `when`(bluetoothController.isBluetoothEnabled).thenReturn(false)
+ }
+
+ fun setBluetoothDisconnected() {
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(false)
+ }
+
+ fun setBluetoothConnected() {
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(true)
+ }
+
+ fun setBluetoothConnecting() {
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(true)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
new file mode 100644
index 000000000000..c2a41d5e41fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2022 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.qs.tiles;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class DreamTileTest extends SysuiTestCase {
+
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private QSLogger mQSLogger;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private IDreamManager mDreamManager;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private UserTracker mUserTracker;
+
+ private TestableLooper mTestableLooper;
+
+ private DreamTile mTile;
+
+ private SecureSettings mSecureSettings;
+
+ private static final ComponentName COLORS_DREAM_COMPONENT_NAME = new ComponentName(
+ "com.android.dreams", ".Colors");
+
+ private static final int DEFAULT_USER = 0;
+
+ private final String mExpectedTileLabel = mContext.getResources().getString(
+ R.string.quick_settings_screensaver_label);
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mSecureSettings = new FakeSettings();
+ mTestableLooper = TestableLooper.get(this);
+
+ when(mHost.getUserId()).thenReturn(DEFAULT_USER);
+ when(mHost.getContext()).thenReturn(mContext);
+
+ mTile = spy(constructTileForTest(true, false));
+
+ mTestableLooper.processAllMessages();
+ mTile.initialize();
+ }
+
+ @Test
+ public void testNotAvailable() throws RemoteException {
+ // Should not be available if screensaver is disabled
+ setScreensaverEnabled(false);
+
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_UNAVAILABLE, mTile.getState().state);
+
+ // Should not be available if component is not set
+ mSecureSettings.putInt(Settings.Secure.SCREENSAVER_ENABLED, 1);
+ when(mDreamManager.getDreamComponents()).thenReturn(null);
+
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_UNAVAILABLE, mTile.getState().state);
+ assertEquals(mExpectedTileLabel, mTile.getState().contentDescription);
+ }
+
+ @Test
+ public void testInactiveWhenDreaming() throws RemoteException {
+ setScreensaverEnabled(true);
+
+ when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{
+ COLORS_DREAM_COMPONENT_NAME
+ });
+ when(mDreamManager.isDreaming()).thenReturn(false);
+
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
+ }
+
+ @Test
+ public void testActive() throws RemoteException {
+ setScreensaverEnabled(true);
+
+ when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{
+ COLORS_DREAM_COMPONENT_NAME
+ });
+ when(mDreamManager.isDreaming()).thenReturn(true);
+
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+ }
+
+ @Test
+ public void testClick() throws RemoteException {
+ // Set the AOSP dream enabled as the base setup.
+ setScreensaverEnabled(true);
+ when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{
+ COLORS_DREAM_COMPONENT_NAME
+ });
+ when(mDreamManager.isDreaming()).thenReturn(false);
+
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
+
+ // Now click
+ mTile.handleClick(null /* view */);
+
+ verify(mDreamManager).dream();
+
+ when(mDreamManager.isDreaming()).thenReturn(true);
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+
+ // Click again to see that other method is called
+ mTile.handleClick(null /* view */);
+
+ verify(mDreamManager).awaken();
+ }
+
+ @Test
+ public void testContentDescription() {
+ assertEquals(mExpectedTileLabel, mTile.getContentDescription(null));
+
+ final String testDreamName = "MyDream";
+ assertEquals(mExpectedTileLabel + ", " + testDreamName,
+ mTile.getContentDescription(testDreamName));
+ }
+
+ @Test
+ public void testUserAvailability() {
+ DreamTile unsupportedTile = constructTileForTest(false, true);
+ assertFalse(unsupportedTile.isAvailable());
+
+ DreamTile supportedTileAllUsers = constructTileForTest(true, false);
+
+ UserHandle systemUserHandle = mock(UserHandle.class);
+ when(systemUserHandle.isSystem()).thenReturn(true);
+
+ UserHandle nonSystemUserHandle = mock(UserHandle.class);
+ when(nonSystemUserHandle.isSystem()).thenReturn(false);
+
+ when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle);
+ assertTrue(supportedTileAllUsers.isAvailable());
+ when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle);
+ assertTrue(supportedTileAllUsers.isAvailable());
+
+ DreamTile supportedTileOnlySystemUser = constructTileForTest(true, true);
+ when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle);
+ assertTrue(supportedTileOnlySystemUser.isAvailable());
+ when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle);
+ assertFalse(supportedTileOnlySystemUser.isAvailable());
+ }
+
+ private void setScreensaverEnabled(boolean enabled) {
+ mSecureSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0,
+ DEFAULT_USER);
+ }
+
+ private DreamTile constructTileForTest(boolean dreamSupported,
+ boolean dreamOnlyEnabledForSystemUser) {
+ return new DreamTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mDreamManager,
+ mSecureSettings,
+ mBroadcastDispatcher,
+ mUserTracker,
+ dreamSupported, dreamOnlyEnabledForSystemUser);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index 55c51b255ac7..e9dfd3ed182b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -36,9 +36,11 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -194,6 +196,26 @@ public class RotationLockTileTest extends SysuiTestCase {
assertEquals("", mLockTile.getState().secondaryLabel.toString());
}
+ @Test
+ public void testIcon_whenDisabled_isOffState() {
+ QSTile.BooleanState state = new QSTile.BooleanState();
+ disableAutoRotation();
+
+ mLockTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_auto_rotate_icon_off));
+ }
+
+ @Test
+ public void testIcon_whenEnabled_isOnState() {
+ QSTile.BooleanState state = new QSTile.BooleanState();
+ enableAutoRotation();
+
+ mLockTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_auto_rotate_icon_on));
+ }
+
private void enableAutoRotation() {
when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(false);
}
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 7b1e5c9f7264..d70370552bb1 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
@@ -32,6 +32,8 @@ import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.ServiceState;
@@ -93,6 +95,12 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Mock
private WifiManager mWifiManager;
@Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private Network mNetwork;
+ @Mock
+ private NetworkCapabilities mNetworkCapabilities;
+ @Mock
private TelephonyManager mTelephonyManager;
@Mock
private SubscriptionManager mSubscriptionManager;
@@ -185,7 +193,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
mInternetDialogController = new InternetDialogController(mContext,
mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
mSubscriptionManager, mTelephonyManager, mWifiManager,
- mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
+ mConnectivityManager, mHandler, mExecutor, mBroadcastDispatcher,
mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController,
mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker,
mLocationController, mDialogLaunchAnimator, mWifiStateWorker);
@@ -199,6 +207,14 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void connectCarrierNetwork_mergedCarrierEntryCanConnect_connectAndCreateSysUiToast() {
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork);
+ when(mConnectivityManager.getNetworkCapabilities(mNetwork))
+ .thenReturn(mNetworkCapabilities);
+ when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(false);
+
when(mMergedCarrierEntry.canConnect()).thenReturn(true);
mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
TOAST_MESSAGE_STRING);
@@ -211,6 +227,52 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
+ public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenSettingsOff() {
+ when(mTelephonyManager.isDataEnabled()).thenReturn(false);
+
+ mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
+ TOAST_MESSAGE_STRING);
+ mInternetDialogController.connectCarrierNetwork();
+
+ verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
+ verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ anyInt());
+ }
+
+ @Test
+ public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenKeyguardLocked() {
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+ mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
+ TOAST_MESSAGE_STRING);
+ mInternetDialogController.connectCarrierNetwork();
+
+ verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
+ verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ anyInt());
+ }
+
+ @Test
+ public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenMobileIsPrimary() {
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork);
+ when(mConnectivityManager.getNetworkCapabilities(mNetwork))
+ .thenReturn(mNetworkCapabilities);
+ when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(true);
+
+ mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
+ TOAST_MESSAGE_STRING);
+ mInternetDialogController.connectCarrierNetwork();
+
+ verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
+ verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+ anyInt());
+ }
+
+ @Test
public void makeOverlayToast_withGravityFlags_addViewWithLayoutParams() {
mTestableResources.addOverride(TOAST_MESSAGE_STRING_ID, TOAST_MESSAGE_STRING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index 32314159f865..a4a89a4c67f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2022 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.shared.animation
import android.testing.AndroidTestingRunner
@@ -7,31 +21,24 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
- @Mock private lateinit var progressProvider: UnfoldTransitionProgressProvider
+ private val progressProvider = TestUnfoldTransitionProvider()
@Mock private lateinit var parent: ViewGroup
- @Captor private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
-
private lateinit var animator: UnfoldConstantTranslateAnimator
- private lateinit var progressListener: TransitionProgressListener
private val viewsIdToRegister =
setOf(
@@ -46,17 +53,14 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider)
animator.init(parent, MAX_TRANSLATION)
-
- verify(progressProvider).addCallback(progressListenerCaptor.capture())
- progressListener = progressListenerCaptor.value
}
@Test
fun onTransition_noMatchingIds() {
// GIVEN no views matching any ids
// WHEN the transition starts
- progressListener.onTransitionStarted()
- progressListener.onTransitionProgress(.1f)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(.1f)
// THEN nothing... no exceptions
}
@@ -86,22 +90,22 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
// Compare values as ints because -0f != 0f
// WHEN the transition starts
- progressListener.onTransitionStarted()
- progressListener.onTransitionProgress(0f)
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0f)
list.forEach { (view, direction) ->
assertEquals((-MAX_TRANSLATION * direction).toInt(), view.translationX.toInt())
}
// WHEN the transition progresses, translation is updated
- progressListener.onTransitionProgress(.5f)
+ progressProvider.onTransitionProgress(.5f)
list.forEach { (view, direction) ->
assertEquals((-MAX_TRANSLATION / 2f * direction).toInt(), view.translationX.toInt())
}
// WHEN the transition ends, translation is completed
- progressListener.onTransitionProgress(1f)
- progressListener.onTransitionFinished()
+ progressProvider.onTransitionProgress(1f)
+ progressProvider.onTransitionFinished()
list.forEach { (view, _) -> assertEquals(0, view.translationX.toInt()) }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
new file mode 100644
index 000000000000..aaa2357a1c52
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 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.shared.clocks
+
+import org.mockito.Mockito.`when` as whenever
+import android.content.Context
+import android.content.ContentResolver
+import android.graphics.drawable.Drawable
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.shared.plugins.PluginManager
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.eq
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ClockRegistryTest : SysuiTestCase() {
+
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockPluginManager: PluginManager
+ @Mock private lateinit var mockClock: Clock
+ @Mock private lateinit var mockThumbnail: Drawable
+ @Mock private lateinit var mockHandler: Handler
+ @Mock private lateinit var mockContentResolver: ContentResolver
+ private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
+ private lateinit var registry: ClockRegistry
+
+ private var settingValue: String = ""
+
+ companion object {
+ private fun failFactory(): Clock {
+ fail("Unexpected call to createClock")
+ return null!!
+ }
+
+ private fun failThumbnail(): Drawable? {
+ fail("Unexpected call to getThumbnail")
+ return null
+ }
+ }
+
+ private class FakeClockPlugin : ClockProviderPlugin {
+ private val metadata = mutableListOf<ClockMetadata>()
+ private val createCallbacks = mutableMapOf<ClockId, () -> Clock>()
+ private val thumbnailCallbacks = mutableMapOf<ClockId, () -> Drawable?>()
+
+ override fun getClocks() = metadata
+ override fun createClock(id: ClockId): Clock = createCallbacks[id]!!()
+ override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!()
+
+ fun addClock(
+ id: ClockId,
+ name: String,
+ create: () -> Clock = ::failFactory,
+ getThumbnail: () -> Drawable? = ::failThumbnail
+ ) {
+ metadata.add(ClockMetadata(id, name))
+ createCallbacks[id] = create
+ thumbnailCallbacks[id] = getThumbnail
+ }
+ }
+
+ @Before
+ fun setUp() {
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+
+ val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
+ registry = object : ClockRegistry(mockContext, mockPluginManager, mockHandler) {
+ override var currentClockId: ClockId
+ get() = settingValue
+ set(value) { settingValue = value }
+ }
+ verify(mockPluginManager).addPluginListener(captor.capture(),
+ eq(ClockProviderPlugin::class.java))
+ pluginListener = captor.value
+ }
+
+ @Test
+ fun pluginRegistration_CorrectState() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3")
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ val list = registry.getClocks()
+ assertEquals(list, listOf(
+ ClockMetadata("clock_1", "clock 1"),
+ ClockMetadata("clock_2", "clock 2"),
+ ClockMetadata("clock_3", "clock 3"),
+ ClockMetadata("clock_4", "clock 4")
+ ))
+ }
+
+ @Test
+ fun clockIdConflict_ErrorWithoutCrash() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
+ plugin1.addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_1", "clock 1")
+ plugin2.addClock("clock_2", "clock 2")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ val list = registry.getClocks()
+ assertEquals(list, listOf(
+ ClockMetadata("clock_1", "clock 1"),
+ ClockMetadata("clock_2", "clock 2")
+ ))
+
+ assertEquals(registry.createExampleClock("clock_1"), mockClock)
+ assertEquals(registry.createExampleClock("clock_2"), mockClock)
+ assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail)
+ assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail)
+ }
+
+ @Test
+ fun createCurrentClock_pluginConnected() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3", { mockClock })
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+
+ val clock = registry.createCurrentClock()
+ assertEquals(clock, mockClock)
+ }
+
+ @Test
+ fun createDefaultClock_pluginDisconnected() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock(DEFAULT_CLOCK_ID, "default", { mockClock })
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3")
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ pluginListener.onPluginDisconnected(plugin2)
+
+ val clock = registry.createCurrentClock()
+ assertEquals(clock, mockClock)
+ }
+
+ @Test
+ fun pluginRemoved_clockChanged() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3", { mockClock })
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+
+ var changeCallCount = 0
+ registry.registerClockChangeListener({ changeCallCount++ })
+
+ pluginListener.onPluginDisconnected(plugin1)
+ assertEquals(0, changeCallCount)
+
+ pluginListener.onPluginDisconnected(plugin2)
+ assertEquals(1, changeCallCount)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index 2cfe6be5c6b2..2f0f0a0a1b8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -26,8 +26,9 @@ import android.view.View
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.dreams.smartspace.DreamsSmartspaceController
+import com.android.systemui.dreams.smartspace.DreamSmartspaceController
import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
import com.android.systemui.util.concurrency.Execution
@@ -39,6 +40,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Spy
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
@@ -74,8 +76,8 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
@Mock
private lateinit var precondition: SmartspacePrecondition
- @Mock
- private lateinit var smartspaceView: BcSmartspaceDataPlugin.SmartspaceView
+ @Spy
+ private var smartspaceView: SmartspaceView = TestView(context)
@Mock
private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
@@ -83,6 +85,8 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
@Mock
private lateinit var session: SmartspaceSession
+ private lateinit var controller: DreamSmartspaceController
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -90,6 +94,9 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
.thenReturn(viewComponent)
`when`(viewComponent.getView()).thenReturn(smartspaceView)
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
+
+ controller = DreamSmartspaceController(context, smartspaceManager, execution, uiExecutor,
+ viewComponentFactory, precondition, Optional.of(targetFilter), Optional.of(plugin))
}
/**
@@ -97,10 +104,6 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
*/
@Test
fun testConnectOnListen() {
- val controller = DreamsSmartspaceController(context,
- smartspaceManager, execution, uiExecutor, viewComponentFactory, precondition,
- Optional.of(targetFilter), Optional.of(plugin))
-
`when`(precondition.conditionsMet()).thenReturn(true)
controller.addListener(listener)
@@ -130,8 +133,7 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
* A class which implements SmartspaceView and extends View. This is mocked to provide the right
* object inheritance and interface implementation used in DreamSmartspaceController
*/
- private class TestView(context: Context?) : View(context),
- BcSmartspaceDataPlugin.SmartspaceView {
+ private class TestView(context: Context?) : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {}
override fun setPrimaryTextColor(color: Int) {}
@@ -160,11 +162,6 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
*/
@Test
fun testConnectOnViewCreate() {
- val controller = DreamsSmartspaceController(context,
- smartspaceManager, execution, uiExecutor, viewComponentFactory, precondition,
- Optional.of(targetFilter),
- Optional.of(plugin))
-
`when`(precondition.conditionsMet()).thenReturn(true)
controller.buildAndConnectView(Mockito.mock(ViewGroup::class.java))
@@ -183,4 +180,16 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
verify(session).close()
}
+
+ /**
+ * Ensures setIsDreaming(true) is called when the view is built.
+ */
+ @Test
+ fun testSetIsDreamingTrueOnViewCreate() {
+ `when`(precondition.conditionsMet()).thenReturn(true)
+
+ controller.buildAndConnectView(Mockito.mock(ViewGroup::class.java))
+
+ verify(smartspaceView).setIsDreaming(true)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 8a388479c0e7..65d0adc99739 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -83,12 +83,10 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
private final class TestableAlertingNotificationManager extends AlertingNotificationManager {
private AlertEntry mLastCreatedEntry;
- private TestableAlertingNotificationManager() {
- super(mock(HeadsUpManagerLogger.class));
+ private TestableAlertingNotificationManager(Handler handler) {
+ super(mock(HeadsUpManagerLogger.class), handler);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
- mHandler.removeCallbacksAndMessages(null);
- mHandler = mTestHandler;
}
@Override
@@ -109,8 +107,8 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
}
}
- protected AlertingNotificationManager createAlertingNotificationManager() {
- return new TestableAlertingNotificationManager();
+ protected AlertingNotificationManager createAlertingNotificationManager(Handler handler) {
+ return new TestableAlertingNotificationManager(handler);
}
protected StatusBarNotification createNewSbn(int id, Notification.Builder n) {
@@ -144,7 +142,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
.build();
mEntry.setRow(mRow);
- mAlertingNotificationManager = createAlertingNotificationManager();
+ mAlertingNotificationManager = createAlertingNotificationManager(mTestHandler);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index d394d7dcebbe..cc69074519ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -45,6 +45,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -59,6 +60,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.Color;
+import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
@@ -106,6 +108,9 @@ import org.mockito.MockitoAnnotations;
import java.text.NumberFormat;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -578,6 +583,80 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
}
@Test
+ public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() {
+ createController();
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(true);
+ String message = "A message";
+
+ mController.setVisible(true);
+ mController.getKeyguardCallback().onBiometricError(
+ FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+ }
+
+ @Test
+ public void doNotSendFaceHelpMessages_fingerprintEnrolled() {
+ createController();
+
+ // GIVEN fingerprint enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(true);
+
+ // WHEN help messages received
+ final String helpString = "helpString";
+ final int[] msgIds = new int[]{
+ BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
+ BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+ };
+ for (int msgId : msgIds) {
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ msgId, helpString + msgId, BiometricSourceType.FACE);
+ }
+
+ // THEN no messages shown
+ verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+ }
+
+ @Test
+ public void sendAllFaceHelpMessages_fingerprintNotEnrolled() {
+ createController();
+
+ // GIVEN fingerprint NOT enrolled
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+ 0)).thenReturn(false);
+
+ // WHEN help messages received
+ final Set<CharSequence> helpStrings = new HashSet<>();
+ final String helpString = "helpString";
+ final int[] msgIds = new int[]{
+ BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
+ BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
+ BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+ };
+ for (int msgId : msgIds) {
+ final String numberedHelpString = helpString + msgId;
+ mKeyguardUpdateMonitorCallback.onBiometricHelp(
+ msgId, numberedHelpString, BiometricSourceType.FACE);
+ helpStrings.add(numberedHelpString);
+ }
+
+ // THEN message shown for each call
+ verifyIndicationMessages(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpStrings);
+ }
+
+ @Test
public void updateMonitor_listenerUpdatesIndication() {
createController();
String restingIndication = "Resting indication";
@@ -789,8 +868,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mExecutor.runAllReady();
reset(mRotateTextViewController);
- // GIVEN keyguard is showing
+ // GIVEN keyguard is showing and not dozing
when(mKeyguardStateController.isShowing()).thenReturn(true);
+ mController.setVisible(true);
+ mExecutor.runAllReady();
+ reset(mRotateTextViewController);
// WHEN keyguard showing changed called
mKeyguardStateControllerCallback.onKeyguardShowingChanged();
@@ -850,6 +932,19 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mBroadcastReceiver.onReceive(mContext, new Intent());
}
+ private void verifyIndicationMessages(int type, Set<CharSequence> messages) {
+ verify(mRotateTextViewController, times(messages.size())).updateIndication(eq(type),
+ mKeyguardIndicationCaptor.capture(), anyBoolean());
+ List<KeyguardIndication> kis = mKeyguardIndicationCaptor.getAllValues();
+
+ for (KeyguardIndication ki : kis) {
+ final CharSequence msg = ki.getMessage();
+ assertTrue(messages.contains(msg)); // check message is shown
+ messages.remove(msg);
+ }
+ assertThat(messages.size()).isEqualTo(0); // check that all messages accounted for (removed)
+ }
+
private void verifyIndicationMessage(int type, String message) {
verify(mRotateTextViewController).updateIndication(eq(type),
mKeyguardIndicationCaptor.capture(), anyBoolean());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 4e7e79f2cb26..95460583e857 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -53,6 +53,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
@@ -1797,6 +1798,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
@Test
public void testStableMultipleSectionOrdering() {
+ // WHEN the list is originally built with reordering disabled
mListBuilder.setSectioners(asList(
new PackageSectioner(PACKAGE_1), new PackageSectioner(PACKAGE_2)));
mStabilityManager.setAllowEntryReordering(false);
@@ -1807,12 +1809,94 @@ public class ShadeListBuilderTest extends SysuiTestCase {
addNotif(3, PACKAGE_1).setRank(3);
dispatchBuild();
+ // VERIFY the order and that entry reordering has not been suppressed
verifyBuiltList(
notif(0),
notif(1),
notif(3),
notif(2)
);
+ verify(mStabilityManager, never()).onEntryReorderSuppressed();
+
+ // WHEN the ranks change
+ setNewRank(notif(0).entry, 4);
+ dispatchBuild();
+
+ // VERIFY the order does not change that entry reordering has been suppressed
+ verifyBuiltList(
+ notif(0),
+ notif(1),
+ notif(3),
+ notif(2)
+ );
+ verify(mStabilityManager).onEntryReorderSuppressed();
+
+ // WHEN reordering is now allowed again
+ mStabilityManager.setAllowEntryReordering(true);
+ dispatchBuild();
+
+ // VERIFY that list order changes
+ verifyBuiltList(
+ notif(1),
+ notif(3),
+ notif(0),
+ notif(2)
+ );
+ }
+
+ @Test
+ public void testStableChildOrdering() {
+ // WHEN the list is originally built with reordering disabled
+ mStabilityManager.setAllowEntryReordering(false);
+ addGroupSummary(0, PACKAGE_1, GROUP_1).setRank(0);
+ addGroupChild(1, PACKAGE_1, GROUP_1).setRank(1);
+ addGroupChild(2, PACKAGE_1, GROUP_1).setRank(2);
+ addGroupChild(3, PACKAGE_1, GROUP_1).setRank(3);
+ dispatchBuild();
+
+ // VERIFY the order and that entry reordering has not been suppressed
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(2),
+ child(3)
+ )
+ );
+ verify(mStabilityManager, never()).onEntryReorderSuppressed();
+
+ // WHEN the ranks change
+ setNewRank(notif(2).entry, 5);
+ dispatchBuild();
+
+ // VERIFY the order does not change that entry reordering has been suppressed
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(2),
+ child(3)
+ )
+ );
+ verify(mStabilityManager).onEntryReorderSuppressed();
+
+ // WHEN reordering is now allowed again
+ mStabilityManager.setAllowEntryReordering(true);
+ dispatchBuild();
+
+ // VERIFY that list order changes
+ verifyBuiltList(
+ group(
+ summary(0),
+ child(1),
+ child(3),
+ child(2)
+ )
+ );
+ }
+
+ private static void setNewRank(NotificationEntry entry, int rank) {
+ entry.setRanking(new RankingBuilder(entry.getRanking()).setRank(rank).build());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 699f77f9b7bb..2ee31265ff7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -59,6 +59,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.ArrayList
+import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -75,6 +76,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
private lateinit var mBeforeFinalizeFilterListener: OnBeforeFinalizeFilterListener
private lateinit var mOnHeadsUpChangedListener: OnHeadsUpChangedListener
private lateinit var mNotifSectioner: NotifSectioner
+ private lateinit var mActionPressListener: Consumer<NotificationEntry>
private val mNotifPipeline: NotifPipeline = mock()
private val mLogger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
@@ -131,6 +133,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
mOnHeadsUpChangedListener = withArgCaptor {
verify(mHeadsUpManager).addListener(capture())
}
+ mActionPressListener = withArgCaptor {
+ verify(mRemoteInputManager).addActionPressListener(capture())
+ }
given(mHeadsUpManager.allEntries).willAnswer { mHuns.stream() }
given(mHeadsUpManager.isAlerting(anyString())).willAnswer { invocation ->
val key = invocation.getArgument<String>(0)
@@ -199,6 +204,19 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun hunExtensionCancelledWhenHunActionPressed() {
+ whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+ addHUN(mEntry)
+ whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
+ whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ mActionPressListener.accept(mEntry)
+ mExecutor.advanceClockToLast()
+ mExecutor.runAllReady()
+ verify(mHeadsUpManager, times(1)).removeNotification(eq(mEntry.key), eq(true))
+ }
+
+ @Test
fun testCancelUpdatedStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 52bacd2360b3..d8a98d1e8ea4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -29,12 +29,12 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index 3b034f7af9a6..8b115fe2d6bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -41,7 +41,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.notification.SectionClassifier;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.ListEntry;
@@ -56,6 +55,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
@@ -96,9 +96,9 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
@Mock private IStatusBarService mService;
@Mock private BindEventManagerImpl mBindEventManagerImpl;
@Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
- private final SectionClassifier mSectionClassifier = new SectionClassifier();
+ private final SectionStyleProvider mSectionStyleProvider = new SectionStyleProvider();
private final NotifUiAdjustmentProvider mAdjustmentProvider =
- new NotifUiAdjustmentProvider(mSectionClassifier);
+ new NotifUiAdjustmentProvider(mSectionStyleProvider);
@NonNull
private NotificationEntryBuilder getNotificationEntryBuilder() {
@@ -446,6 +446,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
mInflateCallbacks.put(entry, callback);
}
+
@Override
public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
@NonNull InflationCallback callback) {
@@ -462,6 +463,10 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
public void invokeInflateCallbackForEntry(NotificationEntry entry) {
getInflateCallback(entry).onInflationFinished(entry, entry.getRowController());
}
+
+ @Override
+ public void releaseViews(@NonNull NotificationEntry entry) {
+ }
}
private void fireAddEvents(List<? extends ListEntry> entries) {
@@ -487,7 +492,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
private static final int TEST_MAX_GROUP_DELAY = 100;
private void setSectionIsLowPriority(boolean minimized) {
- mSectionClassifier.setMinimizedSections(minimized
+ mSectionStyleProvider.setMinimizedSections(minimized
? Collections.singleton(mNotifSection.getSectioner())
: Collections.emptyList());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index f4d8405a796e..ff08bc38c944 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -40,7 +40,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
-import com.android.systemui.statusbar.notification.SectionClassifier;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -48,6 +47,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
@@ -68,7 +68,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private HighPriorityProvider mHighPriorityProvider;
- @Mock private SectionClassifier mSectionClassifier;
+ @Mock private SectionStyleProvider mSectionStyleProvider;
@Mock private NotifPipeline mNotifPipeline;
@Mock private NodeController mAlertingHeaderController;
@Mock private NodeController mSilentNodeController;
@@ -92,7 +92,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mRankingCoordinator = new RankingCoordinator(
mStatusBarStateController,
mHighPriorityProvider,
- mSectionClassifier,
+ mSectionStyleProvider,
mAlertingHeaderController,
mSilentHeaderController,
mSilentNodeController);
@@ -100,7 +100,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mEntry.setRanking(getRankingForUnfilteredNotif().build());
mRankingCoordinator.attach(mNotifPipeline);
- verify(mSectionClassifier).setMinimizedSections(any());
+ verify(mSectionStyleProvider).setMinimizedSections(any());
verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture());
mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0);
mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
index 447ba1510e13..40859d0e6304 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
@@ -21,13 +21,13 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.FeedbackIcon
-import com.android.systemui.statusbar.notification.SectionClassifier
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.statusbar.notification.collection.render.NotifRowController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -53,7 +53,7 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var pipeline: NotifPipeline
@Mock private lateinit var assistantFeedbackController: AssistantFeedbackController
- @Mock private lateinit var sectionClassifier: SectionClassifier
+ @Mock private lateinit var sectionStyleProvider: SectionStyleProvider
@Mock private lateinit var section1: NotifSection
@Mock private lateinit var section2: NotifSection
@@ -66,7 +66,7 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() {
coordinator = RowAppearanceCoordinator(
mContext,
assistantFeedbackController,
- sectionClassifier
+ sectionStyleProvider
)
coordinator.attach(pipeline)
beforeRenderListListener = withArgCaptor {
@@ -82,8 +82,8 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() {
@Test
fun testSetSystemExpandedOnlyOnFirst() {
- whenever(sectionClassifier.isMinimizedSection(eq(section1))).thenReturn(false)
- whenever(sectionClassifier.isMinimizedSection(eq(section1))).thenReturn(false)
+ whenever(sectionStyleProvider.isMinimizedSection(eq(section1))).thenReturn(false)
+ whenever(sectionStyleProvider.isMinimizedSection(eq(section1))).thenReturn(false)
beforeRenderListListener.onBeforeRenderList(listOf(entry1, entry2))
afterRenderEntryListener.onAfterRenderEntry(entry1, controller1)
verify(controller1).setSystemExpanded(eq(true))
@@ -93,8 +93,8 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() {
@Test
fun testSetSystemExpandedNeverIfMinimized() {
- whenever(sectionClassifier.isMinimizedSection(eq(section1))).thenReturn(true)
- whenever(sectionClassifier.isMinimizedSection(eq(section1))).thenReturn(true)
+ whenever(sectionStyleProvider.isMinimizedSection(eq(section1))).thenReturn(true)
+ whenever(sectionStyleProvider.isMinimizedSection(eq(section1))).thenReturn(true)
beforeRenderListListener.onBeforeRenderList(listOf(entry1, entry2))
afterRenderEntryListener.onAfterRenderEntry(entry1, controller1)
verify(controller1).setSystemExpanded(eq(false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index f3aa20ba4527..2f37f8928e79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -136,7 +136,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testScreenOff_groupAndSectionChangesAllowed() {
// GIVEN screen is off, panel isn't expanded and device isn't pulsing
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPanelExpanded(false);
setPulsing(false);
@@ -149,9 +150,42 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
}
@Test
+ public void testScreenTurningOff_groupAndSectionChangesNotAllowed() {
+ // GIVEN the screen is turning off (sleepy but partially dozed)
+ setFullyDozed(false);
+ setSleepy(true);
+ setPanelExpanded(true);
+ setPulsing(false);
+
+ // THEN group changes are NOT allowed
+ assertFalse(mNotifStabilityManager.isGroupChangeAllowed(mEntry));
+ assertFalse(mNotifStabilityManager.isGroupPruneAllowed(mGroupEntry));
+
+ // THEN section changes are NOT allowed
+ assertFalse(mNotifStabilityManager.isSectionChangeAllowed(mEntry));
+ }
+
+ @Test
+ public void testScreenTurningOn_groupAndSectionChangesNotAllowed() {
+ // GIVEN the screen is turning on (still fully dozed, not sleepy)
+ setFullyDozed(true);
+ setSleepy(false);
+ setPanelExpanded(true);
+ setPulsing(false);
+
+ // THEN group changes are NOT allowed
+ assertFalse(mNotifStabilityManager.isGroupChangeAllowed(mEntry));
+ assertFalse(mNotifStabilityManager.isGroupPruneAllowed(mGroupEntry));
+
+ // THEN section changes are NOT allowed
+ assertFalse(mNotifStabilityManager.isSectionChangeAllowed(mEntry));
+ }
+
+ @Test
public void testPanelNotExpanded_groupAndSectionChangesAllowed() {
// GIVEN screen is on but the panel isn't expanded and device isn't pulsing
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(false);
setPulsing(false);
@@ -166,7 +200,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testPanelExpanded_groupAndSectionChangesNotAllowed() {
// GIVEN the panel true expanded and device isn't pulsing
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
setPulsing(false);
@@ -181,7 +216,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testPulsing_screenOff_groupAndSectionChangesNotAllowed() {
// GIVEN the device is pulsing and screen is off
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPulsing(true);
// THEN group changes are NOT allowed
@@ -195,7 +231,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testPulsing_panelNotExpanded_groupAndSectionChangesNotAllowed() {
// GIVEN the device is pulsing and screen is off with the panel not expanded
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPanelExpanded(false);
setPulsing(true);
@@ -211,7 +248,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
public void testOverrideReorderingSuppression_onlySectionChangesAllowed() {
// GIVEN section changes typically wouldn't be allowed because the panel is expanded and
// we're not pulsing
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
setPulsing(true);
@@ -233,7 +271,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testTemporarilyAllowSectionChanges_callsInvalidate() {
// GIVEN section changes typically wouldn't be allowed because the panel is expanded
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
setPulsing(false);
@@ -247,7 +286,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testTemporarilyAllowSectionChanges_noInvalidationCalled() {
// GIVEN section changes typically WOULD be allowed
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPanelExpanded(false);
setPulsing(false);
@@ -261,7 +301,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testTemporarilyAllowSectionChangesTimeout() {
// GIVEN section changes typically WOULD be allowed
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPanelExpanded(false);
setPulsing(false);
assertTrue(mNotifStabilityManager.isSectionChangeAllowed(mEntry));
@@ -292,7 +333,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testTemporarilyAllowSectionChanges_isPulsingChangeBeforeTimeout() {
// GIVEN section changes typically wouldn't be allowed because the device is pulsing
- setScreenOn(false);
+ setFullyDozed(true);
+ setSleepy(true);
setPanelExpanded(false);
setPulsing(true);
@@ -315,8 +357,11 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
// WHEN device isn't pulsing anymore
setPulsing(false);
- // WHEN screen isn't on
- setScreenOn(false);
+ // WHEN fully dozed
+ setFullyDozed(true);
+
+ // WHEN sleepy
+ setSleepy(true);
// WHEN panel isn't expanded
setPanelExpanded(false);
@@ -330,7 +375,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
public void testNotSuppressingGroupChangesAnymore_invalidationCalled() {
// GIVEN visual stability is being maintained b/c panel is expanded
setPulsing(false);
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
assertFalse(mNotifStabilityManager.isGroupChangeAllowed(mEntry));
@@ -399,7 +445,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
public void testNotSuppressingEntryReorderingAnymoreWillInvalidate() {
// GIVEN visual stability is being maintained b/c panel is expanded
setPulsing(false);
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
assertFalse(mNotifStabilityManager.isEntryReorderingAllowed(mEntry));
@@ -417,7 +464,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
public void testQueryingEntryReorderingButNotReportingReorderSuppressedDoesNotInvalidate() {
// GIVEN visual stability is being maintained b/c panel is expanded
setPulsing(false);
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
assertFalse(mNotifStabilityManager.isEntryReorderingAllowed(mEntry));
@@ -432,7 +480,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Test
public void testHeadsUp_allowedToChangeGroupAndSection() {
// GIVEN group + section changes disallowed
- setScreenOn(true);
+ setFullyDozed(false);
+ setSleepy(false);
setPanelExpanded(true);
setPulsing(true);
assertFalse(mNotifStabilityManager.isGroupChangeAllowed(mEntry));
@@ -462,11 +511,16 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
mStatusBarStateListener.onPulsingChanged(pulsing);
}
- private void setScreenOn(boolean screenOn) {
- if (screenOn) {
- mWakefulnessObserver.onStartedWakingUp();
- } else {
+ private void setFullyDozed(boolean fullyDozed) {
+ float dozeAmount = fullyDozed ? 1 : 0;
+ mStatusBarStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
+ }
+
+ private void setSleepy(boolean sleepy) {
+ if (sleepy) {
mWakefulnessObserver.onFinishedGoingToSleep();
+ } else {
+ mWakefulnessObserver.onStartedWakingUp();
}
}
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
index 0e1865861cae..ff601938d544 100644
--- 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
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.collection.render
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
-import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -28,6 +27,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
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.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 8a2dc263cf36..7b40ba87b494 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.interruption;
import static android.app.Notification.FLAG_BUBBLE;
+import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -431,6 +432,17 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
/**
+ * Test that notification can bubble even if it is a child in a group and group settings are
+ * set to alert only for summary notifications.
+ */
+ @Test
+ public void testShouldBubbleUp_notifInGroupWithOnlySummaryAlerts() {
+ ensureStateForBubbleUp();
+ NotificationEntry bubble = createBubble("testgroup", GROUP_ALERT_SUMMARY);
+ assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(bubble)).isTrue();
+ }
+
+ /**
* If the notification doesn't have permission to bubble, it shouldn't bubble.
*/
@Test
@@ -497,16 +509,27 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
private NotificationEntry createBubble() {
+ return createBubble(null, null);
+ }
+
+ private NotificationEntry createBubble(String groupKey, Integer groupAlert) {
Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder(
PendingIntent.getActivity(mContext, 0, new Intent(),
PendingIntent.FLAG_MUTABLE),
Icon.createWithResource(mContext.getResources(), R.drawable.android))
.build();
- Notification n = new Notification.Builder(getContext(), "a")
+ Notification.Builder nb = new Notification.Builder(getContext(), "a")
.setContentTitle("title")
.setContentText("content text")
- .setBubbleMetadata(data)
- .build();
+ .setBubbleMetadata(data);
+ if (groupKey != null) {
+ nb.setGroup(groupKey);
+ nb.setGroupSummary(false);
+ }
+ if (groupAlert != null) {
+ nb.setGroupAlertBehavior(groupAlert);
+ }
+ Notification n = nb.build();
n.flags |= FLAG_BUBBLE;
return new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index eceff7cc6362..3d5be6d1ea77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -148,10 +148,9 @@ public class NotificationTestHelper {
mock(KeyguardBypassController.class),
mock(NotificationGroupManagerLegacy.class),
mock(VisualStabilityProvider.class),
- mock(ConfigurationControllerImpl.class)
+ mock(ConfigurationControllerImpl.class),
+ new Handler(mTestLooper.getLooper())
);
- mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
- mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper());
mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager);
mIconManager = new IconManager(
mock(CommonNotifCollection.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 6864c65c9af4..5d898b65b60c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -128,7 +128,6 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
.thenReturn(true);
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
- when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController,
mKeyguardViewMediator, mScrimController, mShadeController,
@@ -258,11 +257,9 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE, true /* isStrongBiometric */);
- verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
- anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
- .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+ .isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
}
@Test
@@ -277,11 +274,9 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE, true /* isStrongBiometric */);
- verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
- anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
- .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+ .isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
}
@Test
@@ -378,21 +373,6 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
}
@Test
- public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
- when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
- when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
- // the value of isStrongBiometric doesn't matter here since we only care about the returned
- // value of isUnlockingWithBiometricAllowed()
- mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE, true /* isStrongBiometric */);
-
- verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
- assertThat(mBiometricUnlockController.getMode())
- .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
- }
-
- @Test
public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
reset(mUpdateMonitor);
reset(mStatusBarKeyguardViewManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index db5741c90ebc..b8c8b5f26f0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -76,7 +77,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
VisualStabilityProvider visualStabilityProvider,
StatusBarStateController statusBarStateController,
KeyguardBypassController keyguardBypassController,
- ConfigurationController configurationController
+ ConfigurationController configurationController,
+ Handler handler
) {
super(
context,
@@ -85,7 +87,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
keyguardBypassController,
groupManager,
visualStabilityProvider,
- configurationController
+ configurationController,
+ handler
);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
@@ -105,6 +108,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
when(mVSProvider.isReorderingAllowed()).thenReturn(true);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
mDependency.injectMockDependency(ConfigurationController.class);
+ super.setUp();
+
mHeadsUpManager = new TestableHeadsUpManagerPhone(
mContext,
mHeadsUpManagerLogger,
@@ -112,11 +117,9 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
mVSProvider,
mStatusBarStateController,
mBypassController,
- mConfigurationController
+ mConfigurationController,
+ mTestHandler
);
- super.setUp();
- mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
- mHeadsUpManager.mHandler = mTestHandler;
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 9c02216722e2..39021d8732d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -399,9 +399,8 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.hide(false /* destroyView */);
verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
}
-
@Test
- public void testShow_delaysIfFaceAuthIsRunning_unlessBypass() {
+ public void testShow_delaysIfFaceAuthIsRunning_unlessBypassEnabled() {
when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
mBouncer.show(true /* reset */);
@@ -410,6 +409,16 @@ public class KeyguardBouncerTest extends SysuiTestCase {
}
@Test
+ public void testShow_delaysIfFaceAuthIsRunning_unlessFingerprintEnrolled() {
+ when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0))
+ .thenReturn(true);
+ mBouncer.show(true /* reset */);
+
+ verify(mHandler, never()).postDelayed(any(), anyLong());
+ }
+
+ @Test
public void testRegisterUpdateMonitorCallback() {
verify(mKeyguardUpdateMonitor).registerCallback(any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 7070bc19db62..56dfb0cee520 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -51,7 +52,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.wm.shell.bubbles.Bubbles;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -89,7 +89,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mHeadsUpManager = new HeadsUpManager(mContext, mock(HeadsUpManagerLogger.class)) {};
+ mHeadsUpManager = new HeadsUpManager(mContext, mock(HeadsUpManagerLogger.class),
+ mock(Handler.class)) {};
when(mNotificationEntryManager.getPendingNotificationsIterator())
.thenReturn(mPendingEntries.values());
@@ -114,11 +115,6 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
mHeadsUpManager.addListener(mGroupAlertTransferHelper);
}
- @After
- public void tearDown() {
- mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
- }
-
private void mockHasHeadsUpContentView(NotificationEntry entry,
boolean hasHeadsUpContentView) {
RowContentBindParams params = new RowContentBindParams();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 9ab88dc2d764..ba29e953c73d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -136,6 +136,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
private class UnfoldConfig : UnfoldTransitionConfig {
override var isEnabled: Boolean = false
override var isHingeAngleEnabled: Boolean = false
+ override val halfFoldedTimeoutMillis: Int = 0
}
private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
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 09009c6ee260..32df2d790bd1 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
@@ -833,7 +833,7 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
- public void scrimBlanksWhenUnlockingFromPulse() {
+ public void scrimBlankCallbackWhenUnlockingFromPulse() {
boolean[] blanked = {false};
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.PULSING);
@@ -846,7 +846,50 @@ public class ScrimControllerTest extends SysuiTestCase {
}
});
finishAnimationsImmediately();
- Assert.assertTrue("Scrim should blank when unlocking from pulse.", blanked[0]);
+ Assert.assertTrue("Scrim should send display blanked callback when unlocking "
+ + "from pulse.", blanked[0]);
+ }
+
+ @Test
+ public void blankingNotRequired_leavingAoD() {
+ // GIVEN display does NOT need blanking
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
+
+ mScrimController = new ScrimController(mLightBarController,
+ mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
+ new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
+ mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
+ mScreenOffAnimationController,
+ mPanelExpansionStateManager,
+ mKeyguardUnlockAnimationController,
+ mStatusBarKeyguardViewManager);
+ mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
+ mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
+ mScrimController.setAnimatorListener(mAnimatorListener);
+ mScrimController.setHasBackdrop(false);
+ mScrimController.setWallpaperSupportsAmbientMode(false);
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+
+ // WHEN Simulate unlock with fingerprint
+ mScrimController.transitionTo(ScrimState.AOD);
+ finishAnimationsImmediately();
+
+ // WHEN transitioning to UNLOCKED, onDisplayCallbackBlanked callback called to continue
+ // the transition but the scrim was not actually blanked
+ mScrimController.transitionTo(ScrimState.UNLOCKED,
+ new ScrimController.Callback() {
+ @Override
+ public void onDisplayBlanked() {
+ // Front scrim should not be black nor opaque
+ Assert.assertTrue("Scrim should NOT be visible during transition."
+ + " Alpha: " + mScrimInFront.getViewAlpha(),
+ mScrimInFront.getViewAlpha() == 0f);
+ Assert.assertSame("Scrim should not be visible during transition.",
+ mScrimVisibility, TRANSPARENT);
+ }
+ });
+ finishAnimationsImmediately();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 4f2abf263a9b..0c1d04253bf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -61,7 +61,9 @@ import com.google.common.truth.Truth;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
@@ -97,6 +99,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private LatencyTracker mLatencyTracker;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;
@Before
public void setUp() {
@@ -136,6 +139,11 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mBypassController);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
mStatusBarKeyguardViewManager.show(null);
+ ArgumentCaptor<KeyguardBouncer.BouncerExpansionCallback> callbackArgumentCaptor =
+ ArgumentCaptor.forClass(KeyguardBouncer.BouncerExpansionCallback.class);
+ verify(mKeyguardBouncerFactory).create(any(ViewGroup.class),
+ callbackArgumentCaptor.capture());
+ mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
}
@Test
@@ -441,4 +449,24 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
return new PanelExpansionChangeEvent(
fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
}
+
+ @Test
+ public void testReportBouncerOnDreamWhenVisible() {
+ mBouncerExpansionCallback.onVisibilityChanged(true);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ Mockito.clearInvocations(mCentralSurfaces);
+ when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
+ mBouncerExpansionCallback.onVisibilityChanged(true);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(true);
+ }
+
+ @Test
+ public void testReportBouncerOnDreamWhenNotVisible() {
+ mBouncerExpansionCallback.onVisibilityChanged(false);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ Mockito.clearInvocations(mCentralSurfaces);
+ when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
+ mBouncerExpansionCallback.onVisibilityChanged(false);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 6c83e9f88d63..4506e4142784 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -76,7 +76,7 @@ public class SystemUIDialogTest extends SysuiTestCase {
@Test
public void testNoRegisterReceiver() {
- final SystemUIDialog dialog = new SystemUIDialog(mContext, false);
+ final SystemUIDialog dialog = new SystemUIDialog(mContext, 0, false);
dialog.show();
verify(mBroadcastDispatcher, never()).registerReceiver(any(), any(), eq(null), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 6abc687f0ebb..b94aac21acad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -48,7 +48,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DisableFlagsLogger;
import com.android.systemui.statusbar.OperatorNameViewController;
-import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -84,7 +83,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private StatusBarLocationPublisher mLocationPublisher;
// Set in instantiate()
private StatusBarIconController mStatusBarIconController;
- private NetworkController mNetworkController;
private KeyguardStateController mKeyguardStateController;
private final CommandQueue mCommandQueue = mock(CommandQueue.class);
@@ -352,7 +350,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
mStatusBarIconController = mock(StatusBarIconController.class);
- mNetworkController = mock(NetworkController.class);
mStatusBarStateController = mock(StatusBarStateController.class);
mKeyguardStateController = mock(KeyguardStateController.class);
mOperatorNameViewController = mock(OperatorNameViewController.class);
@@ -374,7 +371,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mNotificationPanelViewController,
- mNetworkController,
mStatusBarStateController,
mCommandQueue,
mCarrierConfigTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 424a40058997..f39d6875cffc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -36,6 +36,7 @@ import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -73,8 +74,8 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
@Mock private HeadsUpManagerLogger mLogger;
private final class TestableHeadsUpManager extends HeadsUpManager {
- TestableHeadsUpManager(Context context, HeadsUpManagerLogger logger) {
- super(context, logger);
+ TestableHeadsUpManager(Context context, HeadsUpManagerLogger logger, Handler handler) {
+ super(context, logger, handler);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
@@ -91,10 +92,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
mDependency.injectTestDependency(UiEventLogger.class, mUiEventLoggerFake);
when(mEntry.getSbn()).thenReturn(mSbn);
when(mSbn.getNotification()).thenReturn(mNotification);
- mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger);
+
super.setUp();
- mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
- mHeadsUpManager.mHandler = mTestHandler;
+ mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger, mTestHandler);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 6bd8b98f70e1..e0bf9e7b0081 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy
import android.app.IActivityManager
+import android.app.NotificationManager
import android.app.admin.DevicePolicyManager
import android.content.BroadcastReceiver
import android.content.Context
@@ -38,7 +39,9 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.LatencyTracker
import com.android.internal.util.UserIcons
+import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
+import com.android.systemui.GuestSessionNotification
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
@@ -102,6 +105,11 @@ class UserSwitcherControllerTest : SysuiTestCase() {
@Mock private lateinit var threadedRenderer: ThreadedRenderer
@Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
@Mock private lateinit var globalSettings: GlobalSettings
+ @Mock private lateinit var guestSessionNotification: GuestSessionNotification
+ @Mock private lateinit var guestResetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+ private lateinit var resetSessionDialogFactory:
+ GuestResumeSessionReceiver.ResetSessionDialog.Factory
+ private lateinit var guestResumeSessionReceiver: GuestResumeSessionReceiver
private lateinit var testableLooper: TestableLooper
private lateinit var bgExecutor: FakeExecutor
private lateinit var longRunningExecutor: FakeExecutor
@@ -133,9 +141,28 @@ class UserSwitcherControllerTest : SysuiTestCase() {
com.android.internal.R.bool.config_guestUserAutoCreated, false)
mContext.addMockSystemService(Context.FACE_SERVICE, mock(FaceManager::class.java))
+ mContext.addMockSystemService(Context.NOTIFICATION_SERVICE,
+ mock(NotificationManager::class.java))
mContext.addMockSystemService(Context.FINGERPRINT_SERVICE,
mock(FingerprintManager::class.java))
+ resetSessionDialogFactory = object : GuestResumeSessionReceiver.ResetSessionDialog.Factory {
+ override fun create(userId: Int): GuestResumeSessionReceiver.ResetSessionDialog {
+ return GuestResumeSessionReceiver.ResetSessionDialog(
+ mContext,
+ mock(UserSwitcherController::class.java),
+ uiEventLogger,
+ userId
+ )
+ }
+ }
+
+ guestResumeSessionReceiver = GuestResumeSessionReceiver(userTracker,
+ secureSettings,
+ broadcastDispatcher,
+ guestSessionNotification,
+ resetSessionDialogFactory)
+
`when`(userManager.canAddMoreUsers(eq(UserManager.USER_TYPE_FULL_SECONDARY)))
.thenReturn(true)
`when`(notificationShadeWindowView.context).thenReturn(context)
@@ -198,7 +225,9 @@ class UserSwitcherControllerTest : SysuiTestCase() {
interactionJankMonitor,
latencyTracker,
dumpManager,
- dialogLaunchAnimator)
+ dialogLaunchAnimator,
+ guestResumeSessionReceiver,
+ guestResetOrExitSessionReceiver)
userSwitcherController.init(notificationShadeWindowView)
}
@@ -288,7 +317,10 @@ class UserSwitcherControllerTest : SysuiTestCase() {
.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
testableLooper.processAllMessages()
assertEquals(1, uiEventLogger.numLogs())
- assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE.id, uiEventLogger.eventId(0))
+ assertTrue(
+ QSUserSwitcherEvent.QS_USER_GUEST_REMOVE.id == uiEventLogger.eventId(0) ||
+ QSUserSwitcherEvent.QS_USER_SWITCH.id == uiEventLogger.eventId(0)
+ )
}
@Test
@@ -350,7 +382,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
assertNotNull(userSwitcherController.mExitGuestDialog)
userSwitcherController.mExitGuestDialog
- .getButton(DialogInterface.BUTTON_NEGATIVE).performClick()
+ .getButton(DialogInterface.BUTTON_NEUTRAL).performClick()
testableLooper.processAllMessages()
assertEquals(0, uiEventLogger.numLogs())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
index 8076b4eda883..39e4e6446d02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
@@ -25,28 +25,20 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
-import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.util.TestFoldStateProvider
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class FoldStateLoggingProviderTest : SysuiTestCase() {
- @Captor
- private lateinit var foldUpdatesListener: ArgumentCaptor<FoldStateProvider.FoldUpdatesListener>
-
- @Mock private lateinit var foldStateProvider: FoldStateProvider
-
+ private val testFoldStateProvider = TestFoldStateProvider()
private val fakeClock = FakeSystemClock()
private lateinit var foldStateLoggingProvider: FoldStateLoggingProvider
@@ -65,12 +57,10 @@ class FoldStateLoggingProviderTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
foldStateLoggingProvider =
- FoldStateLoggingProviderImpl(foldStateProvider, fakeClock).apply {
+ FoldStateLoggingProviderImpl(testFoldStateProvider, fakeClock).apply {
addCallback(foldStateLoggingListener)
init()
}
-
- verify(foldStateProvider).addCallback(foldUpdatesListener.capture())
}
@Test
@@ -183,10 +173,10 @@ class FoldStateLoggingProviderTest : SysuiTestCase() {
fun uninit_removesCallback() {
foldStateLoggingProvider.uninit()
- verify(foldStateProvider).removeCallback(foldUpdatesListener.value)
+ assertThat(testFoldStateProvider.hasListeners).isFalse()
}
private fun sendFoldUpdate(@FoldUpdate foldUpdate: Int) {
- foldUpdatesListener.value.onFoldUpdate(foldUpdate)
+ testFoldStateProvider.sendFoldUpdate(foldUpdate)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
new file mode 100644
index 000000000000..ab450e2506f9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.unfold.config
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+/**
+ * A test that checks that we load correct resources in
+ * ResourceUnfoldTransitionConfig as we use strings there instead of R constants.
+ * Internal Android resource constants are not available in public APIs,
+ * so we can't use them there directly.
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ResourceUnfoldTransitionConfigTest : SysuiTestCase() {
+
+ private val config = ResourceUnfoldTransitionConfig()
+
+ @Test
+ fun testIsEnabled() {
+ assertThat(config.isEnabled).isEqualTo(mContext.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled))
+ }
+
+ @Test
+ fun testHingeAngleEnabled() {
+ assertThat(config.isHingeAngleEnabled).isEqualTo(mContext.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle))
+ }
+
+ @Test
+ fun testHalfFoldedTimeout() {
+ assertThat(config.halfFoldedTimeoutMillis).isEqualTo(mContext.resources
+ .getInteger(com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 1f1f88b07ea1..87fca1f23f1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -16,82 +16,69 @@
package com.android.systemui.unfold.updates
-import android.app.ActivityManager
-import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
-import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
-import android.app.WindowConfiguration.ActivityType
-import android.hardware.devicestate.DeviceStateManager
-import android.hardware.devicestate.DeviceStateManager.FoldStateListener
import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
-import com.android.systemui.unfold.util.FoldableDeviceStates
-import com.android.systemui.unfold.util.FoldableTestUtils
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@SmallTest
class DeviceFoldStateProviderTest : SysuiTestCase() {
- @Mock private lateinit var hingeAngleProvider: HingeAngleProvider
-
- @Mock private lateinit var screenStatusProvider: ScreenStatusProvider
-
- @Mock private lateinit var deviceStateManager: DeviceStateManager
-
- @Mock private lateinit var activityManager: ActivityManager
-
- @Mock private lateinit var handler: Handler
-
- @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
+ @Mock
+ private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
- @Captor private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
+ @Mock
+ private lateinit var handler: Handler
- @Captor private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
+ private val foldProvider = TestFoldProvider()
+ private val screenOnStatusProvider = TestScreenOnStatusProvider()
+ private val testHingeAngleProvider = TestHingeAngleProvider()
private lateinit var foldStateProvider: DeviceFoldStateProvider
private val foldUpdates: MutableList<Int> = arrayListOf()
private val hingeAngleUpdates: MutableList<Float> = arrayListOf()
- private lateinit var deviceStates: FoldableDeviceStates
-
private var scheduledRunnable: Runnable? = null
private var scheduledRunnableDelay: Long? = null
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- overrideResource(
- com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout,
- HALF_OPENED_TIMEOUT_MILLIS.toInt())
- deviceStates = FoldableTestUtils.findDeviceStates(context)
+
+ val config = object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
+ override val halfFoldedTimeoutMillis: Int
+ get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
+ }
foldStateProvider =
DeviceFoldStateProvider(
- context,
- hingeAngleProvider,
- screenStatusProvider,
- deviceStateManager,
- activityManager,
+ config,
+ testHingeAngleProvider,
+ screenOnStatusProvider,
+ foldProvider,
+ activityTypeProvider,
context.mainExecutor,
- handler)
+ handler
+ )
foldStateProvider.addCallback(
object : FoldStateProvider.FoldUpdatesListener {
@@ -105,10 +92,6 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
})
foldStateProvider.start()
- verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
- verify(screenStatusProvider).addCallback(screenOnListenerCaptor.capture())
- verify(hingeAngleProvider).addCallback(hingeAngleCaptor.capture())
-
whenever(handler.postDelayed(any<Runnable>(), any())).then { invocationOnMock ->
scheduledRunnable = invocationOnMock.getArgument<Runnable>(0)
scheduledRunnableDelay = invocationOnMock.getArgument<Long>(1)
@@ -125,7 +108,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
}
// By default, we're on launcher.
- setupForegroundActivityType(ACTIVITY_TYPE_HOME)
+ setupForegroundActivityType(isHomeActivity = true)
}
@Test
@@ -146,14 +129,14 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
fun testOnFolded_stopsHingeAngleProvider() {
setFoldState(folded = true)
- verify(hingeAngleProvider).stop()
+ assertThat(testHingeAngleProvider.isStarted).isFalse()
}
@Test
fun testOnUnfolded_startsHingeAngleProvider() {
setFoldState(folded = false)
- verify(hingeAngleProvider).start()
+ assertThat(testHingeAngleProvider.isStarted).isTrue()
}
@Test
@@ -310,7 +293,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
- setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+ setupForegroundActivityType(isHomeActivity = false)
sendHingeAngleEvent(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -319,8 +302,28 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
}
@Test
+ fun startClosingEvent_whileActivityTypeNotAvailable_triggerBeforeThreshold() {
+ setupForegroundActivityType(isHomeActivity = null)
+ sendHingeAngleEvent(180)
+
+ sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startClosingEvent_whileOnLauncher_doesTriggerBeforeThreshold() {
+ setupForegroundActivityType(isHomeActivity = true)
+ sendHingeAngleEvent(180)
+
+ sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
- setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+ setupForegroundActivityType(isHomeActivity = false)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
@@ -328,9 +331,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
- private fun setupForegroundActivityType(@ActivityType type: Int) {
- val taskInfo = RunningTaskInfo().apply { topActivityType = type }
- whenever(activityManager.getRunningTasks(1)).thenReturn(listOf(taskInfo))
+ private fun setupForegroundActivityType(isHomeActivity: Boolean?) {
+ whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity)
}
private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) {
@@ -348,16 +350,72 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
}
private fun setFoldState(folded: Boolean) {
- val state = if (folded) deviceStates.folded else deviceStates.unfolded
- foldStateListenerCaptor.value.onStateChanged(state)
+ foldProvider.notifyFolded(folded)
}
private fun fireScreenOnEvent() {
- screenOnListenerCaptor.value.onScreenTurnedOn()
+ screenOnStatusProvider.notifyScreenTurnedOn()
}
private fun sendHingeAngleEvent(angle: Int) {
- hingeAngleCaptor.value.accept(angle.toFloat())
+ testHingeAngleProvider.notifyAngle(angle.toFloat())
+ }
+
+ private class TestFoldProvider : FoldProvider {
+ private val callbacks = arrayListOf<FoldCallback>()
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ callbacks += callback
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ callbacks -= callback
+ }
+
+ fun notifyFolded(isFolded: Boolean) {
+ callbacks.forEach { it.onFoldUpdated(isFolded) }
+ }
+ }
+
+ private class TestScreenOnStatusProvider : ScreenStatusProvider {
+ private val callbacks = arrayListOf<ScreenListener>()
+
+ override fun addCallback(listener: ScreenListener) {
+ callbacks += listener
+ }
+
+ override fun removeCallback(listener: ScreenListener) {
+ callbacks -= listener
+ }
+
+ fun notifyScreenTurnedOn() {
+ callbacks.forEach { it.onScreenTurnedOn() }
+ }
+ }
+
+ private class TestHingeAngleProvider : HingeAngleProvider {
+ private val callbacks = arrayListOf<Consumer<Float>>()
+ var isStarted: Boolean = false
+
+ override fun start() {
+ isStarted = true;
+ }
+
+ override fun stop() {
+ isStarted = false;
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ callbacks += listener
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ callbacks -= listener
+ }
+
+ fun notifyAngle(angle: Float) {
+ callbacks.forEach { it.accept(angle) }
+ }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
index a3f17aa5ba55..b2cedbf8d606 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
@@ -20,18 +20,18 @@ import android.view.IRotationWatcher
import android.view.IWindowManager
import android.view.Surface
import androidx.test.filters.SmallTest
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
-import com.android.systemui.SysuiTestCase
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -41,16 +41,13 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
@Mock
lateinit var windowManager: IWindowManager
- @Mock
- lateinit var sourceProvider: UnfoldTransitionProgressProvider
+ private val sourceProvider = TestUnfoldTransitionProvider()
@Mock
lateinit var transitionListener: TransitionProgressListener
lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
- private val sourceProviderListenerCaptor =
- ArgumentCaptor.forClass(TransitionProgressListener::class.java)
private val rotationWatcherCaptor =
ArgumentCaptor.forClass(IRotationWatcher.Stub::class.java)
@@ -66,7 +63,6 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
progressProvider.init()
- verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
verify(windowManager).watchRotation(rotationWatcherCaptor.capture(), any())
progressProvider.addCallback(transitionListener)
@@ -76,7 +72,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
fun testNaturalRotation0_sendTransitionStartedEvent_eventReceived() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(transitionListener).onTransitionStarted()
}
@@ -85,7 +81,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
fun testNaturalRotation0_sendTransitionProgressEvent_eventReceived() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionProgress(0.5f)
+ sourceProvider.onTransitionProgress(0.5f)
verify(transitionListener).onTransitionProgress(0.5f)
}
@@ -94,7 +90,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
fun testNotNaturalRotation90_sendTransitionStartedEvent_eventNotReceived() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(transitionListener, never()).onTransitionStarted()
}
@@ -103,7 +99,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
fun testNaturalRotation90_sendTransitionProgressEvent_eventNotReceived() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionProgress(0.5f)
+ sourceProvider.onTransitionProgress(0.5f)
verify(transitionListener, never()).onTransitionProgress(0.5f)
}
@@ -111,7 +107,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
@Test
fun testRotationBecameUnnaturalDuringTransition_sendsTransitionFinishedEvent() {
onRotationChanged(Surface.ROTATION_0)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
clearInvocations(transitionListener)
onRotationChanged(Surface.ROTATION_90)
@@ -122,7 +118,7 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
@Test
fun testRotationBecameNaturalDuringTransition_sendsTransitionStartedEvent() {
onRotationChanged(Surface.ROTATION_90)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
clearInvocations(transitionListener)
onRotationChanged(Surface.ROTATION_0)
@@ -133,7 +129,4 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
private fun onRotationChanged(rotation: Int) {
rotationWatcherCaptor.value.onRotationChanged(rotation)
}
-
- private val source: TransitionProgressListener
- get() = sourceProviderListenerCaptor.value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
index db7a85166807..fc2a78a5ee7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
@@ -21,6 +21,7 @@ import android.database.ContentObserver
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.TestUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
@@ -41,15 +42,11 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
lateinit var contentResolver: ContentResolver
@Mock
- lateinit var sourceProvider: UnfoldTransitionProgressProvider
-
- @Mock
lateinit var sinkProvider: TransitionProgressListener
- lateinit var progressProvider: ScaleAwareTransitionProgressProvider
+ private val sourceProvider = TestUnfoldTransitionProvider()
- private val sourceProviderListenerCaptor =
- ArgumentCaptor.forClass(TransitionProgressListener::class.java)
+ lateinit var progressProvider: ScaleAwareTransitionProgressProvider
private val animatorDurationScaleListenerCaptor =
ArgumentCaptor.forClass(ContentObserver::class.java)
@@ -63,7 +60,6 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
contentResolver
)
- verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
verify(contentResolver).registerContentObserver(any(), any(),
animatorDurationScaleListenerCaptor.capture())
@@ -74,7 +70,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionStarted_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verify(sinkProvider).onTransitionStarted()
}
@@ -83,7 +79,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionStarted_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionStarted()
+ sourceProvider.onTransitionStarted()
verifyNoMoreInteractions(sinkProvider)
}
@@ -92,7 +88,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionEnd_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionFinished()
+ sourceProvider.onTransitionFinished()
verify(sinkProvider).onTransitionFinished()
}
@@ -101,7 +97,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionEnd_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionFinished()
+ sourceProvider.onTransitionFinished()
verifyNoMoreInteractions(sinkProvider)
}
@@ -110,7 +106,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionProgress_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
- source.onTransitionProgress(42f)
+ sourceProvider.onTransitionProgress(42f)
verify(sinkProvider).onTransitionProgress(42f)
}
@@ -119,7 +115,7 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
fun onTransitionProgress_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
- source.onTransitionProgress(42f)
+ sourceProvider.onTransitionProgress(42f)
verifyNoMoreInteractions(sinkProvider)
}
@@ -133,7 +129,4 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
ValueAnimator.setDurationScale(durationScale)
animatorDurationScaleListenerCaptor.value.dispatchChange(/* selfChange= */false)
}
-
- private val source: TransitionProgressListener
- get() = sourceProviderListenerCaptor.value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
index 8f851ec60981..a064e8c81076 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
@@ -24,6 +24,8 @@ import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
class TestFoldStateProvider : FoldStateProvider {
private val listeners: MutableList<FoldUpdatesListener> = arrayListOf()
+ val hasListeners: Boolean
+ get() = listeners.isNotEmpty()
override fun start() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
index c7bcdefdc4c3..900d7928fb44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
@@ -28,7 +28,6 @@ import android.util.ArraySet;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.NotificationChannels;
import org.junit.Before;
import org.junit.Test;
@@ -41,7 +40,7 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ChannelsTest extends SysuiTestCase {
+public class NotificationChannelsTest extends SysuiTestCase {
private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
@Before
@@ -55,9 +54,10 @@ public class ChannelsTest extends SysuiTestCase {
NotificationChannels.ALERTS,
NotificationChannels.SCREENSHOTS_HEADSUP,
NotificationChannels.STORAGE,
- NotificationChannels.GENERAL,
+ NotificationChannels.INSTANT,
NotificationChannels.BATTERY,
- NotificationChannels.HINTS
+ NotificationChannels.HINTS,
+ NotificationChannels.SETUP
));
NotificationChannels.createAll(mContext);
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
@@ -67,4 +67,11 @@ public class ChannelsTest extends SysuiTestCase {
list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId())));
}
+ @Test
+ public void testChannelCleanup() {
+ new NotificationChannels(mContext).start();
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mMockNotificationManager).deleteNotificationChannel(captor.capture());
+ assertEquals(NotificationChannels.GENERAL, captor.getValue());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
index 5118637ea710..758961658f2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
@@ -65,7 +65,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
mCondition3 = spy(new FakeCondition());
mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3));
- mConditionMonitor = new Monitor(mExecutor, mConditions, null /*callbacks*/);
+ mConditionMonitor = new Monitor(mExecutor, mConditions);
}
@Test
@@ -76,8 +76,10 @@ public class ConditionMonitorTest extends SysuiTestCase {
final Monitor monitor = new Monitor(
mExecutor,
- new HashSet<>(Arrays.asList(overridingCondition, regularCondition)),
- new HashSet<>(Arrays.asList(callback)));
+ new HashSet<>(Arrays.asList(overridingCondition, regularCondition)));
+
+ monitor.addCallback(callback);
+ mExecutor.runAllReady();
when(overridingCondition.isOverridingCondition()).thenReturn(true);
when(overridingCondition.isConditionMet()).thenReturn(true);
@@ -123,8 +125,9 @@ public class ConditionMonitorTest extends SysuiTestCase {
final Monitor monitor = new Monitor(
mExecutor,
new HashSet<>(Arrays.asList(overridingCondition, overridingCondition2,
- regularCondition)),
- new HashSet<>(Arrays.asList(callback)));
+ regularCondition)));
+ monitor.addCallback(callback);
+ mExecutor.runAllReady();
when(overridingCondition.isOverridingCondition()).thenReturn(true);
when(overridingCondition.isConditionMet()).thenReturn(true);
@@ -174,8 +177,8 @@ public class ConditionMonitorTest extends SysuiTestCase {
mock(Monitor.Callback.class);
final Condition condition = mock(Condition.class);
when(condition.isConditionMet()).thenReturn(true);
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
- new HashSet<>(Arrays.asList(callback1)));
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)));
+ monitor.addCallback(callback1);
final Monitor.Callback callback2 =
mock(Monitor.Callback.class);
@@ -186,7 +189,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void addCallback_noConditions_reportAllConditionsMet() {
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>());
final Monitor.Callback callback = mock(Monitor.Callback.class);
monitor.addCallback(callback);
@@ -196,7 +199,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void addCallback_withMultipleInstancesOfTheSameCallback_registerOnlyOne() {
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>());
final Monitor.Callback callback = mock(Monitor.Callback.class);
// Adds the same instance multiple times.
@@ -212,8 +215,7 @@ public class ConditionMonitorTest extends SysuiTestCase {
@Test
public void removeCallback_shouldNoLongerReceiveUpdate() {
final Condition condition = mock(Condition.class);
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
- null);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)));
final Monitor.Callback callback =
mock(Monitor.Callback.class);
monitor.addCallback(callback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index 33ef9cf7a9c5..1baac84d5ca6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -46,11 +46,6 @@ public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
}
@Override
- public boolean hasEmergencyCryptKeeperText() {
- return false;
- }
-
- @Override
public boolean isRadioOn() {
return false;
}
diff --git a/packages/SystemUI/tools/lint/baseline.xml b/packages/SystemUI/tools/lint/baseline.xml
index 9a2e3207a6f4..301c9b831c3b 100644
--- a/packages/SystemUI/tools/lint/baseline.xml
+++ b/packages/SystemUI/tools/lint/baseline.xml
@@ -337,17 +337,6 @@
<issue
id="Deprecated"
message="`android:singleLine` is deprecated: Use `maxLines=&quot;1&quot;` instead"
- errorLine1=" android:singleLine=&quot;true&quot;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/layout/emergency_cryptkeeper_text.xml"
- line="25"
- column="9"/>
- </issue>
-
- <issue
- id="Deprecated"
- message="`android:singleLine` is deprecated: Use `maxLines=&quot;1&quot;` instead"
errorLine1=" android:singleLine=&quot;true&quot;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -88997,17 +88986,6 @@
errorLine1=" android:paddingStart=&quot;6dp&quot;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/layout/emergency_cryptkeeper_text.xml"
- line="24"
- column="9"/>
- </issue>
-
- <issue
- id="RtlSymmetry"
- message="When you define `paddingStart` you should probably also define `paddingEnd` for right-to-left symmetry"
- errorLine1=" android:paddingStart=&quot;6dp&quot;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
file="res/layout/heads_up_status_bar_layout.xml"
line="43"
column="9"/>
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
new file mode 100644
index 000000000000..108295b90e58
--- /dev/null
+++ b/packages/SystemUI/unfold/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "SystemUIUnfoldLib",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ "src/**/*.aidl",
+ ],
+ static_libs: [
+ "androidx.dynamicanimation_dynamicanimation",
+ "dagger2",
+ "jsr330",
+ ],
+ java_version: "1.8",
+ min_sdk_version: "current",
+ plugins: ["dagger2-compiler"],
+}
diff --git a/packages/SystemUI/unfold/AndroidManifest.xml b/packages/SystemUI/unfold/AndroidManifest.xml
new file mode 100644
index 000000000000..ee8afe1aff5b
--- /dev/null
+++ b/packages/SystemUI/unfold/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.unfold">
+
+
+</manifest>
diff --git a/packages/SystemUI/unfold/lint-baseline.xml b/packages/SystemUI/unfold/lint-baseline.xml
new file mode 100644
index 000000000000..449ed2e60853
--- /dev/null
+++ b/packages/SystemUI/unfold/lint-baseline.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev">
+</issues>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 9e5aeb84b624..a5ec0a454412 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -16,16 +16,16 @@
package com.android.systemui.unfold
-import android.app.ActivityManager
import android.content.ContentResolver
import android.content.Context
import android.hardware.SensorManager
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
+import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
import dagger.BindsInstance
import dagger.Component
@@ -51,12 +51,12 @@ internal interface UnfoldSharedComponent {
@BindsInstance context: Context,
@BindsInstance config: UnfoldTransitionConfig,
@BindsInstance screenStatusProvider: ScreenStatusProvider,
- @BindsInstance deviceStateManager: DeviceStateManager,
- @BindsInstance activityManager: ActivityManager,
+ @BindsInstance foldProvider: FoldProvider,
+ @BindsInstance activityTypeProvider: CurrentActivityTypeProvider,
@BindsInstance sensorManager: SensorManager,
- @BindsInstance @Main handler: Handler,
- @BindsInstance @Main executor: Executor,
- @BindsInstance @UiBackground backgroundExecutor: Executor,
+ @BindsInstance @UnfoldMain handler: Handler,
+ @BindsInstance @UnfoldMain executor: Executor,
+ @BindsInstance @UnfoldBackground backgroundExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index c612995241ef..8f4ee4dc9838 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -17,8 +17,8 @@
package com.android.systemui.unfold
import android.hardware.SensorManager
-import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldBackground
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
@@ -70,7 +70,7 @@ class UnfoldSharedModule {
fun hingeAngleProvider(
config: UnfoldTransitionConfig,
sensorManager: SensorManager,
- @UiBackground executor: Executor
+ @UnfoldBackground executor: Executor
): HingeAngleProvider =
if (config.isHingeAngleEnabled) {
HingeSensorAngleProvider(sensorManager, executor)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index cc56007c431a..402dd8474bc4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -17,14 +17,13 @@
package com.android.systemui.unfold
-import android.app.ActivityManager
import android.content.Context
import android.hardware.SensorManager
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
-import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import java.util.concurrent.Executor
/**
@@ -39,8 +38,8 @@ fun createUnfoldTransitionProgressProvider(
context: Context,
config: UnfoldTransitionConfig,
screenStatusProvider: ScreenStatusProvider,
- deviceStateManager: DeviceStateManager,
- activityManager: ActivityManager,
+ foldProvider: FoldProvider,
+ activityTypeProvider: CurrentActivityTypeProvider,
sensorManager: SensorManager,
mainHandler: Handler,
mainExecutor: Executor,
@@ -52,8 +51,8 @@ fun createUnfoldTransitionProgressProvider(
context,
config,
screenStatusProvider,
- deviceStateManager,
- activityManager,
+ foldProvider,
+ activityTypeProvider,
sensorManager,
mainHandler,
mainExecutor,
@@ -64,5 +63,3 @@ fun createUnfoldTransitionProgressProvider(
?: throw IllegalStateException(
"Trying to create " +
"UnfoldTransitionProgressProvider when the transition is disabled")
-
-fun createConfig(context: Context): UnfoldTransitionConfig = ResourceUnfoldTransitionConfig(context)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
index 409dc95ab131..d54481c72bfd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
@@ -15,9 +15,9 @@
*/
package com.android.systemui.unfold
-import android.annotation.FloatRange
-import com.android.systemui.statusbar.policy.CallbackController
+import androidx.annotation.FloatRange
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.CallbackController
/**
* Interface that allows to receive unfold transition progress updates.
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
new file mode 100644
index 000000000000..2044f05664d0
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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.unfold.compat
+
+import android.content.Context
+import android.content.res.Configuration
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
+
+/**
+ * Fold provider that notifies about fold state based on the screen size
+ * It could be used when no activity context is available
+ * TODO(b/232369816): use Jetpack WM library when non-activity contexts supported b/169740873
+ */
+class ScreenSizeFoldProvider(private val context: Context) : FoldProvider {
+
+ private var callbacks: MutableList<FoldCallback> = arrayListOf()
+ private var lastWidth: Int = 0
+
+ override fun registerCallback(callback: FoldCallback, executor: Executor) {
+ callbacks += callback
+ onConfigurationChange(context.resources.configuration)
+ }
+
+ override fun unregisterCallback(callback: FoldCallback) {
+ callbacks -= callback
+ }
+
+ fun onConfigurationChange(newConfig: Configuration) {
+ if (lastWidth == newConfig.smallestScreenWidthDp) {
+ return
+ }
+
+ if (newConfig.smallestScreenWidthDp > INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP) {
+ callbacks.forEach { it.onFoldUpdated(false) }
+ } else {
+ callbacks.forEach { it.onFoldUpdated(true) }
+ }
+ lastWidth = newConfig.smallestScreenWidthDp
+ }
+}
+
+private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
new file mode 100644
index 000000000000..c405f3110297
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.unfold.compat
+
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import java.util.concurrent.Executor
+
+class SizeScreenStatusProvider(
+ private val foldProvider: FoldProvider,
+ private val executor: Executor
+) : ScreenStatusProvider {
+
+ private val listeners: MutableList<ScreenListener> = arrayListOf()
+ private val callback = object : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ if (!isFolded) {
+ listeners.forEach { it.onScreenTurnedOn() }
+ }
+ }
+ }
+
+ fun start() {
+ foldProvider.registerCallback(
+ callback,
+ executor
+ )
+ }
+
+ fun stop() {
+ foldProvider.unregisterCallback(callback)
+ }
+
+ override fun addCallback(listener: ScreenListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: ScreenListener) {
+ listeners.remove(listener)
+ }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
new file mode 100644
index 000000000000..c51372975a67
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.unfold.config
+
+import android.content.res.Resources
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ResourceUnfoldTransitionConfig @Inject constructor() : UnfoldTransitionConfig {
+
+ override val isEnabled: Boolean by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionEnabled", "bool", "android")
+ Resources.getSystem().getBoolean(id)
+ }
+
+ override val isHingeAngleEnabled: Boolean by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionHingeAngle", "bool", "android")
+ Resources.getSystem().getBoolean(id)
+ }
+
+ override val halfFoldedTimeoutMillis: Int by lazy {
+ val id = Resources.getSystem()
+ .getIdentifier("config_unfoldTransitionHalfFoldedTimeout", "integer", "android")
+ Resources.getSystem().getInteger(id)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
index 5b187b3486c6..765e862aa00d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
@@ -18,4 +18,5 @@ package com.android.systemui.unfold.config
interface UnfoldTransitionConfig {
val isEnabled: Boolean
val isHingeAngleEnabled: Boolean
+ val halfFoldedTimeoutMillis: Int
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
new file mode 100644
index 000000000000..60747954dac3
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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.unfold.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * Alternative to [UiBackground] qualifier annotation in unfold module.
+ * It is needed as we can't depend on SystemUI code in this module.
+ */
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnfoldBackground
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
new file mode 100644
index 000000000000..5553690fb562
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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.unfold.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * Alternative to [Main] qualifier annotation in unfold module.
+ * It is needed as we can't depend on SystemUI code in this module.
+ */
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnfoldMain
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
index 4c85b055aeae..4c85b055aeae 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 04d920cb15d5..2ab28c65f32f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,7 +16,6 @@
package com.android.systemui.unfold.progress
import android.util.Log
-import android.util.MathUtils.saturate
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
@@ -70,6 +69,9 @@ class PhysicsBasedUnfoldTransitionProgressProvider(
springAnimation.animateToFinalPosition(progress)
}
+ private fun saturate(amount: Float, low: Float = 0f, high: Float = 1f): Float =
+ if (amount < low) low else if (amount > high) high else amount
+
override fun onFoldUpdate(@FoldUpdate update: Int) {
when (update) {
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 14581ccd5c0a..e8038fd7dfa6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -15,46 +15,46 @@
*/
package com.android.systemui.unfold.updates
-import android.annotation.FloatRange
-import android.app.ActivityManager
-import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
-import android.content.Context
-import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
import android.util.Log
+import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
import androidx.core.util.Consumer
-import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
import com.android.systemui.unfold.updates.hinge.FULLY_CLOSED_DEGREES
import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import java.util.concurrent.Executor
import javax.inject.Inject
class DeviceFoldStateProvider
@Inject
constructor(
- context: Context,
+ config: UnfoldTransitionConfig,
private val hingeAngleProvider: HingeAngleProvider,
private val screenStatusProvider: ScreenStatusProvider,
- private val deviceStateManager: DeviceStateManager,
- private val activityManager: ActivityManager,
- @Main private val mainExecutor: Executor,
- @Main private val handler: Handler
+ private val foldProvider: FoldProvider,
+ private val activityTypeProvider: CurrentActivityTypeProvider,
+ @UnfoldMain private val mainExecutor: Executor,
+ @UnfoldMain private val handler: Handler
) : FoldStateProvider {
private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf()
- @FoldUpdate private var lastFoldUpdate: Int? = null
+ @FoldUpdate
+ private var lastFoldUpdate: Int? = null
- @FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
+ @FloatRange(from = 0.0, to = 180.0)
+ private var lastHingeAngle: Float = 0f
private val hingeAngleListener = HingeAngleListener()
private val screenListener = ScreenStatusListener()
- private val foldStateListener = FoldStateListener(context)
+ private val foldStateListener = FoldStateListener()
private val timeoutRunnable = TimeoutRunnable()
/**
@@ -62,22 +62,20 @@ constructor(
* [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not
* reached.
*/
- private val halfOpenedTimeoutMillis: Int =
- context.resources.getInteger(
- com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout)
+ private val halfOpenedTimeoutMillis: Int = config.halfFoldedTimeoutMillis
private var isFolded = false
private var isUnfoldHandled = true
override fun start() {
- deviceStateManager.registerCallback(mainExecutor, foldStateListener)
+ foldProvider.registerCallback(foldStateListener, mainExecutor)
screenStatusProvider.addCallback(screenListener)
hingeAngleProvider.addCallback(hingeAngleListener)
}
override fun stop() {
screenStatusProvider.removeCallback(screenListener)
- deviceStateManager.unregisterCallback(foldStateListener)
+ foldProvider.unregisterCallback(foldStateListener)
hingeAngleProvider.removeCallback(hingeAngleListener)
hingeAngleProvider.stop()
}
@@ -92,13 +90,13 @@ constructor(
override val isFinishedOpening: Boolean
get() = !isFolded &&
- (lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN ||
- lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN)
+ (lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN ||
+ lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN)
private val isTransitionInProgress: Boolean
get() =
lastFoldUpdate == FOLD_UPDATE_START_OPENING ||
- lastFoldUpdate == FOLD_UPDATE_START_CLOSING
+ lastFoldUpdate == FOLD_UPDATE_START_CLOSING
private fun onHingeAngle(angle: Float) {
if (DEBUG) {
@@ -136,39 +134,36 @@ constructor(
* apps that support table-top/HALF_FOLDED mode. Only for launcher, there is no threshold.
*/
private fun getClosingThreshold(): Int? {
- val activityType =
- activityManager.getRunningTasks(/* maxNum= */ 1)?.getOrNull(0)?.topActivityType
- ?: return null
+ val isHomeActivity = activityTypeProvider.isHomeActivity ?: return null
if (DEBUG) {
- Log.d(TAG, "activityType=" + activityType)
+ Log.d(TAG, "isHomeActivity=$isHomeActivity")
}
- return if (activityType == ACTIVITY_TYPE_HOME) {
+ return if (isHomeActivity) {
null
} else {
START_CLOSING_ON_APPS_THRESHOLD_DEGREES
}
}
- private inner class FoldStateListener(context: Context) :
- DeviceStateManager.FoldStateListener(
- context,
- { folded: Boolean ->
- isFolded = folded
- lastHingeAngle = FULLY_CLOSED_DEGREES
-
- if (folded) {
- hingeAngleProvider.stop()
- notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
- cancelTimeout()
- isUnfoldHandled = false
- } else {
- notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
- rescheduleAbortAnimationTimeout()
- hingeAngleProvider.start()
- }
- })
+ private inner class FoldStateListener : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ this@DeviceFoldStateProvider.isFolded = isFolded
+ lastHingeAngle = FULLY_CLOSED_DEGREES
+
+ if (isFolded) {
+ hingeAngleProvider.stop()
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
+ cancelTimeout()
+ isUnfoldHandled = false
+ } else {
+ notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
+ rescheduleAbortAnimationTimeout()
+ hingeAngleProvider.start()
+ }
+ }
+ }
private fun notifyFoldUpdate(@FoldUpdate update: Int) {
if (DEBUG) {
@@ -234,7 +229,9 @@ private const val TAG = "DeviceFoldProvider"
private const val DEBUG = false
/** Threshold after which we consider the device fully unfolded. */
-@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
+@VisibleForTesting
+const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
/** Fold animation on top of apps only when the angle exceeds this threshold. */
-@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
+@VisibleForTesting
+const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
new file mode 100644
index 000000000000..6e87beeb295f
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 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.unfold.updates
+
+import java.util.concurrent.Executor
+
+interface FoldProvider {
+ fun registerCallback(callback: FoldCallback, executor: Executor)
+ fun unregisterCallback(callback: FoldCallback)
+
+ interface FoldCallback {
+ fun onFoldUpdated(isFolded: Boolean)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index 14a3a70fc6b0..c7a8bf336777 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -15,10 +15,10 @@
*/
package com.android.systemui.unfold.updates
-import android.annotation.FloatRange
-import android.annotation.IntDef
-import com.android.systemui.statusbar.policy.CallbackController
+import androidx.annotation.FloatRange
+import androidx.annotation.IntDef
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.unfold.util.CallbackController
/**
* Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
@@ -36,7 +36,6 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
}
@IntDef(
- prefix = ["FOLD_UPDATE_"],
value =
[
FOLD_UPDATE_START_OPENING,
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
new file mode 100644
index 000000000000..e985506bd989
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 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.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+
+internal object EmptyHingeAngleProvider : HingeAngleProvider {
+ override fun start() {}
+
+ override fun stop() {}
+
+ override fun removeCallback(listener: Consumer<Float>) {}
+
+ override fun addCallback(listener: Consumer<Float>) {}
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
new file mode 100644
index 000000000000..e464c3f81546
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+import com.android.systemui.unfold.util.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.
+ */
+interface HingeAngleProvider : CallbackController<Consumer<Float>> {
+ fun start()
+ fun stop()
+}
+
+const val FULLY_OPEN_DEGREES = 180f
+const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index c93412b53817..3fc5d610dc2d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2022 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.unfold.updates.hinge
import android.hardware.Sensor
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
index 668c69442cac..d95e050474de 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.unfold.updates.screen
-import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.unfold.util.CallbackController
interface ScreenStatusProvider : CallbackController<ScreenListener> {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
index 1574c8d37ab1..d8bc01804f14 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2022 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.unfold.util
import android.os.Trace
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt
new file mode 100644
index 000000000000..46ad534722cd
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CallbackController.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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.unfold.util
+
+interface CallbackController<T> {
+ fun addCallback(listener: T)
+ fun removeCallback(listener: T)
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
new file mode 100644
index 000000000000..d0e6cdc9a3c6
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/CurrentActivityTypeProvider.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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.unfold.util
+
+interface CurrentActivityTypeProvider {
+ val isHomeActivity: Boolean?
+}
+
+class EmptyCurrentActivityTypeProvider(override val isHomeActivity: Boolean? = null) :
+ CurrentActivityTypeProvider
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index dfe87921dd42..5c92b3499835 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2022 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.unfold.util
import android.animation.ValueAnimator
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
index 8491f832b740..8491f832b740 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml
index cd8ee8d89474..08ab9aea93cb 100644
--- a/packages/VpnDialogs/res/values-gl/strings.xml
+++ b/packages/VpnDialogs/res/values-gl/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"Configurar"</string>
<string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
<string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
- <string name="dismiss" msgid="6192859333764711227">"Ignorar"</string>
+ <string name="dismiss" msgid="6192859333764711227">"Pechar"</string>
</resources>
diff --git a/packages/VpnDialogs/res/values-iw/strings.xml b/packages/VpnDialogs/res/values-iw/strings.xml
index 81903d2b2442..56d810591400 100644
--- a/packages/VpnDialogs/res/values-iw/strings.xml
+++ b/packages/VpnDialogs/res/values-iw/strings.xml
@@ -32,6 +32,6 @@
<string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"‏לשינוי של הגדרות ה-VPN"</string>
<string name="configure" msgid="4905518375574791375">"הגדרה"</string>
<string name="disconnect" msgid="971412338304200056">"נתק"</string>
- <string name="open_app" msgid="3717639178595958667">"לאפליקציה"</string>
+ <string name="open_app" msgid="3717639178595958667">"פתיחת האפליקציה"</string>
<string name="dismiss" msgid="6192859333764711227">"סגירה"</string>
</resources>
diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml
index 0ed2e84b80fa..de18abafb9eb 100644
--- a/packages/VpnDialogs/res/values-km/strings.xml
+++ b/packages/VpnDialogs/res/values-km/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"កំណត់​រចនាសម្ព័ន្ធ"</string>
<string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
<string name="open_app" msgid="3717639178595958667">"បើកកម្មវិធី"</string>
- <string name="dismiss" msgid="6192859333764711227">"បដិសេធ"</string>
+ <string name="dismiss" msgid="6192859333764711227">"ច្រានចោល"</string>
</resources>
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index 0604b47cdb50..4c5c2591986f 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -29,7 +29,7 @@
<string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇ ରହିବା ପାଇଁ ସେଟଅପ୍‍ କରାଯାଇଛି। ଆପଣଙ୍କ ଫୋନ୍‍, <xliff:g id="VPN_APP_1">%1$s</xliff:g> ସହ କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏକ ପବ୍ଲିକ୍‍ ନେଟ୍‌ୱର୍କ ବ୍ୟବହାର କରିବ।"</string>
<string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇରହିବାକୁ ସେଟଅପ୍‍ କରାଯାଇଛି, କିନ୍ତୁ ଏହା ବର୍ତ୍ତମାନ କନେକ୍ଟ କରିପାରୁ ନାହିଁ। VPN ପୁଣି କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଆପଣଙ୍କର କୌଣସି କନେକ୍ସନ୍‌ ରହିବନାହିଁ।"</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
- <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ୍ ବଦଳାନ୍ତୁ"</string>
+ <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ ବଦଳାନ୍ତୁ"</string>
<string name="configure" msgid="4905518375574791375">"କନଫିଗର୍‍ କରନ୍ତୁ"</string>
<string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
<string name="open_app" msgid="3717639178595958667">"ଆପ୍‌ ଖୋଲନ୍ତୁ"</string>
diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml
index 0b4ce4df9514..eb73baad00b4 100644
--- a/packages/VpnDialogs/res/values-sq/strings.xml
+++ b/packages/VpnDialogs/res/values-sq/strings.xml
@@ -33,5 +33,5 @@
<string name="configure" msgid="4905518375574791375">"Konfiguro"</string>
<string name="disconnect" msgid="971412338304200056">"Shkëputu"</string>
<string name="open_app" msgid="3717639178595958667">"Hap aplikacionin"</string>
- <string name="dismiss" msgid="6192859333764711227">"Largoje"</string>
+ <string name="dismiss" msgid="6192859333764711227">"Hiq"</string>
</resources>
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index dfa34bb50805..0a4ecb227548 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -286,10 +286,18 @@ message SystemMessage {
// Package: android
NOTE_MTE_OVERRIDE_ENABLED = 69;
+ // Notify the user that this is a guest session with information
+ // about first login and ephemeral state
+ // Package: android
+ NOTE_GUEST_SESSION = 70;
+
// Inform the user of notification permissions changes.
// Package: android
NOTE_REVIEW_NOTIFICATION_PERMISSIONS = 71;
+ // Notify the user to setup their dock
+ NOTE_SETUP_DOCK = 72;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/Android.bp b/services/Android.bp
index 70692a63ff0f..1e4ce19f1541 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -102,6 +102,7 @@ filegroup {
":services.profcollect-sources",
":services.restrictions-sources",
":services.searchui-sources",
+ ":services.selectiontoolbar-sources",
":services.smartspace-sources",
":services.speech-sources",
":services.systemcaptions-sources",
@@ -157,6 +158,7 @@ java_library {
"services.profcollect",
"services.restrictions",
"services.searchui",
+ "services.selectiontoolbar",
"services.smartspace",
"services.speech",
"services.systemcaptions",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9920cc7e8444..87bfef78bb00 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -557,12 +557,17 @@ public class AccessibilityWindowManager {
shouldClearAccessibilityFocus = mAccessibilityFocusedWindowId
!= AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
+
+ boolean hasWindowIgnore = false;
if (windowCount > 0) {
for (int i = 0; i < windowCount; i++) {
final WindowInfo windowInfo = windows.get(i);
final AccessibilityWindowInfo window;
if (mTrackingWindows) {
window = populateReportedWindowLocked(userId, windowInfo);
+ if (window == null) {
+ hasWindowIgnore = true;
+ }
} else {
window = null;
}
@@ -591,6 +596,13 @@ public class AccessibilityWindowManager {
}
}
final int accessibilityWindowCount = mWindows.size();
+ // Re-order the window layer of all windows in the windows list because there's
+ // window not been added into the windows list.
+ if (hasWindowIgnore) {
+ for (int i = 0; i < accessibilityWindowCount; i++) {
+ mWindows.get(i).setLayer(accessibilityWindowCount - 1 - i);
+ }
+ }
if (isTopFocusedDisplay) {
if (mTouchInteractionInProgress && activeWindowGone) {
mActiveWindowId = mTopFocusedWindowId;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 2cf0e3e54326..9a257e54cf41 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -45,6 +45,7 @@ import android.content.Context;
import android.graphics.Region;
import android.os.Handler;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Slog;
import android.view.Display;
import android.view.InputDevice;
@@ -84,12 +85,14 @@ import java.util.List;
public class TouchExplorer extends BaseEventStreamTransformation
implements GestureManifold.Listener {
- static final boolean DEBUG = false;
private static final long LOGGING_FLAGS = FLAGS_GESTURE | FLAGS_INPUT_FILTER;
// Tag for logging received events.
private static final String LOG_TAG = "TouchExplorer";
+ // To enable these logs, run: 'adb shell setprop log.tag.TouchExplorer DEBUG' (requires restart)
+ static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
+
// The maximum of the cosine between the vectors of two moving
// pointers so they can be considered moving in the same direction.
private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index 23cded771cae..35a1508317c9 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -193,6 +193,6 @@ class MagnificationGesturesObserver implements GesturesObserver.Listener {
@Override
public String toString() {
return "MagnificationGesturesObserver{"
- + ", mDelayedEventQueue=" + mDelayedEventQueue + '}';
+ + "mDelayedEventQueue=" + mDelayedEventQueue + '}';
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 9ff51eecba1d..cf30a5acb030 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -28,12 +28,14 @@ import android.annotation.Nullable;
import android.annotation.UiContext;
import android.content.Context;
import android.graphics.Point;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.MathUtils;
import android.util.Slog;
import android.view.Display;
import android.view.MotionEvent;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
@@ -91,6 +93,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private final Context mContext;
private final Point mTempPoint = new Point();
+ private long mTripleTapAndHoldStartedTime = 0;
+
public WindowMagnificationGestureHandler(@UiContext Context context,
WindowMagnificationManager windowMagnificationMgr,
AccessibilityTraceManager trace,
@@ -213,15 +217,39 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
}
- private void onTripleTapAndHold(MotionEvent up) {
+ @VisibleForTesting
+ void onTripleTapAndHold(MotionEvent up) {
if (DEBUG_DETECTING) {
Slog.i(mLogTag, "onTripleTapAndHold()");
}
enableWindowMagnifier(up.getX(), up.getY(),
WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
+ mTripleTapAndHoldStartedTime = SystemClock.uptimeMillis();
transitionTo(mViewportDraggingState);
}
+ @VisibleForTesting
+ void releaseTripleTapAndHold() {
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
+ transitionTo(mDetectingState);
+ if (mTripleTapAndHoldStartedTime != 0) {
+ final long duration = SystemClock.uptimeMillis() - mTripleTapAndHoldStartedTime;
+ logMagnificationTripleTapAndHoldSession(duration);
+ mTripleTapAndHoldStartedTime = 0;
+ }
+ }
+
+ /**
+ * Logs the duration for the magnification session which is activated by the triple tap and
+ * hold gesture.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ @VisibleForTesting
+ void logMagnificationTripleTapAndHoldSession(long duration) {
+ AccessibilityStatsLogUtils.logMagnificationTripleTapAndHoldSession(duration);
+ }
+
void resetToDetectState() {
transitionTo(mDetectingState);
}
@@ -310,7 +338,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
@Override
public String toString() {
return "PanningScalingState{"
- + "mPanningScalingHandler =" + mPanningScalingHandler + '}';
+ + "mPanningScalingHandler=" + mPanningScalingHandler + '}';
}
}
@@ -370,8 +398,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
case ACTION_UP:
case ACTION_CANCEL: {
- mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
- transitionTo(mDetectingState);
+ releaseTripleTapAndHold();
}
break;
}
@@ -447,7 +474,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
@Override
public String toString() {
return "DetectingState{"
- + ", mGestureTimeoutObserver =" + mGesturesObserver
+ + "mGestureTimeoutObserver=" + mGesturesObserver
+ '}';
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ca116e35eb56..09c6ca3a4734 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -45,6 +45,7 @@ import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
@@ -54,6 +55,7 @@ import com.android.server.wm.WindowManagerInternal;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
/**
* A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper}
@@ -136,6 +138,7 @@ public class WindowMagnificationManager implements
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
// Whether the following typing focus feature for magnification is enabled.
private boolean mMagnificationFollowTypingEnabled = true;
+ @GuardedBy("mLock")
private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray();
private boolean mReceiverRegistered = false;
@@ -465,18 +468,43 @@ public class WindowMagnificationManager implements
}
}
+ private void pauseTrackingTypingFocusRecord(int displayId) {
+ WindowMagnifier magnifier;
+ synchronized (mLock) {
+ magnifier = mWindowMagnifiers.get(displayId);
+ if (magnifier == null) {
+ return;
+ }
+ }
+ magnifier.pauseTrackingTypingFocusRecord();
+ }
+
/**
* Called when the IME window visibility changed.
*
* @param shown {@code true} means the IME window shows on the screen. Otherwise, it's hidden.
*/
void onImeWindowVisibilityChanged(int displayId, boolean shown) {
- mIsImeVisibleArray.put(displayId, shown);
+ synchronized (mLock) {
+ mIsImeVisibleArray.put(displayId, shown);
+ }
if (shown) {
enableAllTrackingTypingFocus();
+ } else {
+ pauseTrackingTypingFocusRecord(displayId);
}
}
+ boolean isImeVisible(int displayId) {
+ synchronized (mLock) {
+ return mIsImeVisibleArray.get(displayId);
+ }
+ }
+
+ void logTrackingTypingFocus(long duration) {
+ AccessibilityStatsLogUtils.logMagnificationFollowTypingFocusSession(duration);
+ }
+
@Override
public boolean processScroll(int displayId, float distanceX, float distanceY) {
moveWindowMagnification(displayId, -distanceX, -distanceY);
@@ -969,6 +997,12 @@ public class WindowMagnificationManager implements
private boolean mTrackingTypingFocusEnabled = true;
+ private volatile long mTrackingTypingFocusStartTime = 0;
+ private static final AtomicLongFieldUpdater<WindowMagnifier> SUM_TIME_UPDATER =
+ AtomicLongFieldUpdater.newUpdater(WindowMagnifier.class,
+ "mTrackingTypingFocusSumTime");
+ private volatile long mTrackingTypingFocusSumTime = 0;
+
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
@@ -1017,6 +1051,7 @@ public class WindowMagnificationManager implements
mEnabled = false;
mIdOfLastServiceToControl = INVALID_SERVICE_ID;
mTrackingTypingFocusEnabled = false;
+ pauseTrackingTypingFocusRecord();
return true;
}
return false;
@@ -1069,6 +1104,14 @@ public class WindowMagnificationManager implements
}
void setTrackingTypingFocusEnabled(boolean trackingTypingFocusEnabled) {
+ if (mWindowMagnificationManager.isWindowMagnifierEnabled(mDisplayId)
+ && mWindowMagnificationManager.isImeVisible(mDisplayId)
+ && trackingTypingFocusEnabled) {
+ startTrackingTypingFocusRecord();
+ }
+ if (mTrackingTypingFocusEnabled && !trackingTypingFocusEnabled) {
+ stopAndLogTrackingTypingFocusRecordIfNeeded();
+ }
mTrackingTypingFocusEnabled = trackingTypingFocusEnabled;
}
@@ -1076,6 +1119,44 @@ public class WindowMagnificationManager implements
return mTrackingTypingFocusEnabled;
}
+ void startTrackingTypingFocusRecord() {
+ if (mTrackingTypingFocusStartTime == 0) {
+ mTrackingTypingFocusStartTime = SystemClock.uptimeMillis();
+ if (DBG) {
+ Slog.d(TAG, "start: mTrackingTypingFocusStartTime = "
+ + mTrackingTypingFocusStartTime);
+ }
+ }
+ }
+
+ void pauseTrackingTypingFocusRecord() {
+ if (mTrackingTypingFocusStartTime != 0) {
+ final long elapsed = (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime);
+ // update mTrackingTypingFocusSumTime value in an atomic operation
+ SUM_TIME_UPDATER.addAndGet(this, elapsed);
+ mTrackingTypingFocusStartTime = 0;
+ if (DBG) {
+ Slog.d(TAG, "pause: mTrackingTypingFocusSumTime = "
+ + mTrackingTypingFocusSumTime + ", elapsed = " + elapsed);
+ }
+ }
+ }
+
+ void stopAndLogTrackingTypingFocusRecordIfNeeded() {
+ if (mTrackingTypingFocusStartTime != 0 || mTrackingTypingFocusSumTime != 0) {
+ final long elapsed = mTrackingTypingFocusStartTime != 0
+ ? (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime) : 0;
+ final long duration = mTrackingTypingFocusSumTime + elapsed;
+ if (DBG) {
+ Slog.d(TAG, "stop and log: session duration = " + duration
+ + ", elapsed = " + elapsed);
+ }
+ mWindowMagnificationManager.logTrackingTypingFocus(duration);
+ mTrackingTypingFocusStartTime = 0;
+ mTrackingTypingFocusSumTime = 0;
+ }
+ }
+
boolean isEnabled() {
return mEnabled;
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 8fe57e18ea37..40110e775ef9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -25,6 +25,8 @@ import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -252,11 +254,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private boolean mSafeMode;
private int mMaxWidgetBitmapMemory;
private boolean mIsProviderInfoPersisted;
+ private boolean mIsCombinedBroadcastEnabled;
AppWidgetServiceImpl(Context context) {
mContext = context;
}
+ @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)
public void onStart() {
mPackageManager = AppGlobals.getPackageManager();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -272,6 +276,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mIsProviderInfoPersisted = !ActivityManager.isLowRamDeviceStatic()
&& DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.PERSISTS_WIDGET_PROVIDER_INFO, true);
+ mIsCombinedBroadcastEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.COMBINED_BROADCAST_ENABLED, true);
if (DEBUG_PROVIDER_INFO_CACHE && !mIsProviderInfoPersisted) {
Slog.d(TAG, "App widget provider info will not be persisted on this device");
}
@@ -1091,16 +1097,16 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
final int widgetCount = provider.widgets.size();
if (widgetCount == 1) {
- // Tell the provider that it's ready.
- sendEnableIntentLocked(provider);
+ // If we are binding the very first widget from a provider, we will send
+ // a combined broadcast or 2 separate broadcasts to tell the provider that
+ // it's ready, and we need them to provide the update now.
+ sendEnableAndUpdateIntentLocked(provider, new int[]{appWidgetId});
+ } else {
+ // For any widget other then the first one, we just send update intent
+ // as we normally would.
+ sendUpdateIntentLocked(provider, new int[]{appWidgetId});
}
- // Send an update now -- We need this update now, and just for this appWidgetId.
- // It's less critical when the next one happens, so when we schedule the next one,
- // we add updatePeriodMillis to its start time. That time will have some slop,
- // but that's okay.
- sendUpdateIntentLocked(provider, new int[] {appWidgetId});
-
// Schedule the future updates.
registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets));
@@ -1444,6 +1450,40 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
@Override
+ public void notifyProviderInheritance(@Nullable final ComponentName[] componentNames) {
+ final int userId = UserHandle.getCallingUserId();
+ if (DEBUG) {
+ Slog.i(TAG, "notifyProviderInheritance() " + userId);
+ }
+
+ if (componentNames == null) {
+ return;
+ }
+
+ for (ComponentName componentName : componentNames) {
+ if (componentName == null) {
+ return;
+ }
+ mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
+ }
+ synchronized (mLock) {
+ ensureGroupStateLoadedLocked(userId);
+
+ for (ComponentName componentName : componentNames) {
+ final ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
+ final Provider provider = lookupProviderLocked(providerId);
+
+ if (provider == null || provider.info == null) {
+ return;
+ }
+
+ provider.info.isExtendedFromAppWidgetProvider = true;
+ }
+ saveGroupStateAsync(userId);
+ }
+ }
+
+ @Override
public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds,
int viewId) {
final int userId = UserHandle.getCallingUserId();
@@ -2297,6 +2337,22 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
cancelBroadcastsLocked(provider);
}
+ private void sendEnableAndUpdateIntentLocked(@NonNull Provider p, int[] appWidgetIds) {
+ final boolean canSendCombinedBroadcast = mIsCombinedBroadcastEnabled && p.info != null
+ && p.info.isExtendedFromAppWidgetProvider;
+ if (!canSendCombinedBroadcast) {
+ // If this function is called by mistake, send two separate broadcasts instead
+ sendEnableIntentLocked(p);
+ sendUpdateIntentLocked(p, appWidgetIds);
+ return;
+ }
+
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+ intent.setComponent(p.id.componentName);
+ sendBroadcastAsUser(intent, p.id.getProfile());
+ }
+
private void sendEnableIntentLocked(Provider p) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
intent.setComponent(p.id.componentName);
@@ -2788,7 +2844,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (provider.widgets.size() > 0) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"appwidget init " + provider.id.componentName.getPackageName());
- sendEnableIntentLocked(provider);
provider.widgets.forEach(widget -> {
widget.trackingUpdate = true;
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
@@ -2797,7 +2852,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
Log.i(TAG, "Widget update scheduled on unlock " + widget.toString());
});
int[] appWidgetIds = getWidgetIds(provider.widgets);
- sendUpdateIntentLocked(provider, appWidgetIds);
+ sendEnableAndUpdateIntentLocked(provider, appWidgetIds);
registerForBroadcastsLocked(provider, appWidgetIds);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index 6a5dcc8c5945..92435d0219f9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -57,6 +57,7 @@ public class AppWidgetXmlUtil {
private static final String ATTR_WIDGET_CATEGORY = "widget_category";
private static final String ATTR_WIDGET_FEATURES = "widget_features";
private static final String ATTR_DESCRIPTION_RES = "description_res";
+ private static final String ATTR_PROVIDER_INHERITANCE = "provider_inheritance";
private static final String ATTR_OS_FINGERPRINT = "os_fingerprint";
/**
@@ -93,6 +94,7 @@ public class AppWidgetXmlUtil {
out.attributeInt(null, ATTR_WIDGET_CATEGORY, info.widgetCategory);
out.attributeInt(null, ATTR_WIDGET_FEATURES, info.widgetFeatures);
out.attributeInt(null, ATTR_DESCRIPTION_RES, info.descriptionRes);
+ out.attributeBoolean(null, ATTR_PROVIDER_INHERITANCE, info.isExtendedFromAppWidgetProvider);
out.attribute(null, ATTR_OS_FINGERPRINT, Build.FINGERPRINT);
}
@@ -133,6 +135,8 @@ public class AppWidgetXmlUtil {
info.widgetCategory = parser.getAttributeInt(null, ATTR_WIDGET_CATEGORY, 0);
info.widgetFeatures = parser.getAttributeInt(null, ATTR_WIDGET_FEATURES, 0);
info.descriptionRes = parser.getAttributeInt(null, ATTR_DESCRIPTION_RES, 0);
+ info.isExtendedFromAppWidgetProvider = parser.getAttributeBoolean(null,
+ ATTR_PROVIDER_INHERITANCE, false);
return info;
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 15d3fa9a03c4..54f77b1e7928 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -361,7 +361,7 @@ public final class AutofillManagerService
@Override // from SystemService
public boolean isUserSupported(TargetUser user) {
- return user.isFull() || user.isManagedProfile();
+ return user.isFull() || user.isProfile();
}
@Override // from SystemService
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
new file mode 100644
index 000000000000..715697d82cad
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
@@ -0,0 +1,293 @@
+/*
+ * 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.autofill;
+
+import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.ICancellationSignal;
+import android.os.RemoteException;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.SaveInfo;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Maintains a client suggestions session with the
+ * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
+ *
+ */
+final class ClientSuggestionsSession {
+
+ private static final String TAG = "ClientSuggestionsSession";
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
+
+ private final int mSessionId;
+ private final IAutoFillManagerClient mClient;
+ private final Handler mHandler;
+ private final ComponentName mComponentName;
+
+ private final RemoteFillService.FillServiceCallbacks mCallbacks;
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private AndroidFuture<FillResponse> mPendingFillRequest;
+ @GuardedBy("mLock")
+ private int mPendingFillRequestId = INVALID_REQUEST_ID;
+
+ ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
+ ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
+ mSessionId = sessionId;
+ mClient = client;
+ mHandler = handler;
+ mComponentName = componentName;
+ mCallbacks = callbacks;
+ }
+
+ void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
+ final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
+ final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
+ final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
+
+ mHandler.post(() -> {
+ if (sVerbose) {
+ Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
+ }
+
+ try {
+ mClient.requestFillFromClient(requestId, inlineRequest,
+ new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
+ } catch (RemoteException e) {
+ fillRequest.completeExceptionally(e);
+ }
+ });
+
+ fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
+ futureRef.set(fillRequest);
+
+ synchronized (mLock) {
+ mPendingFillRequest = fillRequest;
+ mPendingFillRequestId = requestId;
+ }
+
+ fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
+ synchronized (mLock) {
+ mPendingFillRequest = null;
+ mPendingFillRequestId = INVALID_REQUEST_ID;
+ }
+ if (err == null) {
+ processAutofillId(res);
+ mCallbacks.onFillRequestSuccess(requestId, res,
+ mComponentName.getPackageName(), flags);
+ } else {
+ Slog.e(TAG, "Error calling on client fill request", err);
+ if (err instanceof TimeoutException) {
+ dispatchCancellationSignal(cancellationSink.get());
+ mCallbacks.onFillRequestTimeout(requestId);
+ } else if (err instanceof CancellationException) {
+ dispatchCancellationSignal(cancellationSink.get());
+ } else {
+ mCallbacks.onFillRequestFailure(requestId, err.getMessage());
+ }
+ }
+ }));
+ }
+
+ /**
+ * Gets the application info for the component.
+ */
+ @Nullable
+ static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
+ try {
+ ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
+ comp.getPackageName(),
+ PackageManager.GET_META_DATA,
+ userId);
+ if (si != null) {
+ return si;
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Gets the user-visible name of the application.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
+ return appInfo == null ? null : appInfo.loadSafeLabel(
+ context.getPackageManager(), 0 /* do not ellipsize */,
+ TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
+ }
+
+ /**
+ * Gets the user-visible icon of the application.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
+ return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
+ }
+
+ int cancelCurrentRequest() {
+ synchronized (mLock) {
+ return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
+ ? mPendingFillRequestId
+ : INVALID_REQUEST_ID;
+ }
+ }
+
+ /**
+ * The {@link AutofillId} which the client gets from its view is not contain the session id,
+ * but Autofill framework is using the {@link AutofillId} with a session id. So before using
+ * those ids in the Autofill framework, applies the current session id.
+ *
+ * @param res which response need to apply for a session id
+ */
+ private void processAutofillId(FillResponse res) {
+ if (res == null) {
+ return;
+ }
+
+ final List<Dataset> datasets = res.getDatasets();
+ if (datasets != null && !datasets.isEmpty()) {
+ for (int i = 0; i < datasets.size(); i++) {
+ final Dataset dataset = datasets.get(i);
+ if (dataset != null) {
+ applySessionId(dataset.getFieldIds());
+ }
+ }
+ }
+
+ final SaveInfo saveInfo = res.getSaveInfo();
+ if (saveInfo != null) {
+ applySessionId(saveInfo.getOptionalIds());
+ applySessionId(saveInfo.getRequiredIds());
+ applySessionId(saveInfo.getSanitizerValues());
+ applySessionId(saveInfo.getTriggerId());
+ }
+ }
+
+ private void applySessionId(List<AutofillId> ids) {
+ if (ids == null || ids.isEmpty()) {
+ return;
+ }
+
+ for (int i = 0; i < ids.size(); i++) {
+ applySessionId(ids.get(i));
+ }
+ }
+
+ private void applySessionId(AutofillId[][] ids) {
+ if (ids == null) {
+ return;
+ }
+ for (int i = 0; i < ids.length; i++) {
+ applySessionId(ids[i]);
+ }
+ }
+
+ private void applySessionId(AutofillId[] ids) {
+ if (ids == null) {
+ return;
+ }
+ for (int i = 0; i < ids.length; i++) {
+ applySessionId(ids[i]);
+ }
+ }
+
+ private void applySessionId(AutofillId id) {
+ if (id == null) {
+ return;
+ }
+ id.setSessionId(mSessionId);
+ }
+
+ private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
+ if (signal == null) {
+ return;
+ }
+ try {
+ signal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error requesting a cancellation", e);
+ }
+ }
+
+ private class FillCallbackImpl extends IFillCallback.Stub {
+ final AndroidFuture<FillResponse> mFillRequest;
+ final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
+ final AtomicReference<ICancellationSignal> mCancellationSink;
+
+ FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
+ AtomicReference<AndroidFuture<FillResponse>> futureRef,
+ AtomicReference<ICancellationSignal> cancellationSink) {
+ mFillRequest = fillRequest;
+ mFutureRef = futureRef;
+ mCancellationSink = cancellationSink;
+ }
+
+ @Override
+ public void onCancellable(ICancellationSignal cancellation) {
+ AndroidFuture<FillResponse> future = mFutureRef.get();
+ if (future != null && future.isCancelled()) {
+ dispatchCancellationSignal(cancellation);
+ } else {
+ mCancellationSink.set(cancellation);
+ }
+ }
+
+ @Override
+ public void onSuccess(FillResponse response) {
+ mFillRequest.complete(response);
+ }
+
+ @Override
+ public void onFailure(int requestId, CharSequence message) {
+ String errorMessage = message == null ? "" : String.valueOf(message);
+ mFillRequest.completeExceptionally(
+ new RuntimeException(errorMessage));
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0fe9f8f90cea..9f9846117a29 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -33,6 +33,7 @@ import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
+import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
@@ -66,6 +67,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -370,6 +372,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
+ @Nullable
+ private ClientSuggestionsSession mClientSuggestionsSession;
+
// TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
// new one per Session.
private final BroadcastReceiver mDelayedFillBroadcastReceiver =
@@ -466,6 +471,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
/** Whether the current {@link FillResponse} is expired. */
private boolean mExpiredResponse;
+ /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
+ private boolean mClientSuggestionsEnabled;
+
/** Whether the fill dialog UI is disabled. */
private boolean mFillDialogDisabled;
}
@@ -496,14 +504,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
mWaitForInlineRequest = inlineSuggestionsRequest != null;
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
- maybeRequestFillLocked();
+ mWaitForInlineRequest = inlineSuggestionsRequest != null;
+ maybeRequestFillFromServiceLocked();
viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} : null;
}
+ void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
+ mPendingFillRequest = null;
+ mWaitForInlineRequest = inlineRequest != null;
+ mPendingInlineSuggestionsRequest = inlineRequest;
+ }
+
@GuardedBy("mLock")
- void maybeRequestFillLocked() {
+ void maybeRequestFillFromServiceLocked() {
if (mPendingFillRequest == null) {
return;
}
@@ -513,10 +528,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
- mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
- mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
- mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest,
- mPendingFillRequest.getDelayedFillIntentSender());
+ if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(),
+ mPendingInlineSuggestionsRequest,
+ mPendingFillRequest.getDelayedFillIntentSender());
+ }
}
mLastFillRequest = mPendingFillRequest;
@@ -628,7 +647,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
: mDelayedFillPendingIntent.getIntentSender());
mPendingFillRequest = request;
- maybeRequestFillLocked();
+ maybeRequestFillFromServiceLocked();
}
if (mActivityToken != null) {
@@ -853,30 +872,39 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
- * Cancels the last request sent to the {@link #mRemoteFillService}.
+ * Cancels the last request sent to the {@link #mRemoteFillService} or the
+ * {@link #mClientSuggestionsSession}.
*/
@GuardedBy("mLock")
private void cancelCurrentRequestLocked() {
- if (mRemoteFillService == null) {
- wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
- + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+ if (mRemoteFillService == null && mClientSuggestionsSession == null) {
+ wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
+ + "client suggestions session. mForAugmentedAutofillOnly: %s",
+ mSessionFlags.mAugmentedAutofillOnly);
return;
}
- final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
- // Remove the FillContext as there will never be a response for the service
- if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
- final int numContexts = mContexts.size();
+ if (mRemoteFillService != null) {
+ final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
- // It is most likely the last context, hence search backwards
- for (int i = numContexts - 1; i >= 0; i--) {
- if (mContexts.get(i).getRequestId() == canceledRequest) {
- if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
- mContexts.remove(i);
- break;
+ // Remove the FillContext as there will never be a response for the service
+ if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+ final int numContexts = mContexts.size();
+
+ // It is most likely the last context, hence search backwards
+ for (int i = numContexts - 1; i >= 0; i--) {
+ if (mContexts.get(i).getRequestId() == canceledRequest) {
+ if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+ mContexts.remove(i);
+ break;
+ }
}
}
}
+
+ if (mClientSuggestionsSession != null) {
+ mClientSuggestionsSession.cancelCurrentRequest();
+ }
}
private boolean isViewFocusedLocked(int flags) {
@@ -942,17 +970,30 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// structure is taken. This causes only one fill request per burst of focus changes.
cancelCurrentRequestLocked();
- // Only ask IME to create inline suggestions request if Autofill provider supports it and
- // the render service is available except the autofill is triggered manually and the view
- // is also not focused.
+ // Only ask IME to create inline suggestions request when
+ // 1. Autofill provider supports it or client enabled client suggestions.
+ // 2. The render service is available.
+ // 3. The view is focused. (The view may not be focused if the autofill is triggered
+ // manually.)
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
- if (mSessionFlags.mInlineSupportedByService
+ if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
&& remoteRenderService != null
- && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
- Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
- mAssistReceiver.newAutofillRequestLocked(viewState,
- /* isInlineRequest= */ true);
+ && (isViewFocusedLocked(flags) || (isRequestSupportFillDialog(flags)))) {
+ final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
+ if (mSessionFlags.mClientSuggestionsEnabled) {
+ final int finalRequestId = requestId;
+ inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
+ // Using client suggestions
+ synchronized (mLock) {
+ onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
+ }
+ viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
+ };
+ } else {
+ inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
+ viewState, /* isInlineRequest= */ true);
+ }
if (inlineSuggestionsRequestConsumer != null) {
final AutofillId focusedId = mCurrentViewId;
final int requestIdCopy = requestId;
@@ -968,10 +1009,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
);
viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
+ } else if (mSessionFlags.mClientSuggestionsEnabled) {
+ // Request client suggestions for the dropdown mode
+ onClientFillRequestLocked(requestId, null);
} else {
mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
}
+ if (mSessionFlags.mClientSuggestionsEnabled) {
+ // Using client suggestions, unnecessary request AssistStructure
+ return;
+ }
+
// Now request the assist structure data.
requestAssistStructureLocked(requestId, flags);
}
@@ -1036,6 +1085,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
+ mSessionFlags.mClientSuggestionsEnabled =
+ (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
setClientLocked(client);
}
@@ -1147,12 +1198,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
- processNullResponseLocked(requestId, requestFlags);
+ processNullResponseOrFallbackLocked(requestId, requestFlags);
return;
}
fieldClassificationIds = response.getFieldClassificationIds();
- if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
+ if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
+ && !mService.isFieldClassificationEnabledLocked()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestId, requestFlags);
return;
@@ -1237,6 +1289,26 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ @GuardedBy("mLock")
+ private void processNullResponseOrFallbackLocked(int requestId, int flags) {
+ if (!mSessionFlags.mClientSuggestionsEnabled) {
+ processNullResponseLocked(requestId, flags);
+ return;
+ }
+
+ // fallback to the default platform password manager
+ mSessionFlags.mClientSuggestionsEnabled = false;
+
+ final InlineSuggestionsRequest inlineRequest =
+ (mLastInlineSuggestionsRequest != null
+ && mLastInlineSuggestionsRequest.first == requestId)
+ ? mLastInlineSuggestionsRequest.second : null;
+ mAssistReceiver.newAutofillRequestLocked(inlineRequest);
+ requestAssistStructureLocked(requestId,
+ flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
+ return;
+ }
+
// FillServiceCallbacks
@Override
public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
@@ -3245,13 +3317,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
filterText = value.getTextValue().toString();
}
- final CharSequence serviceLabel;
- final Drawable serviceIcon;
+ final CharSequence targetLabel;
+ final Drawable targetIcon;
synchronized (mLock) {
- serviceLabel = mService.getServiceLabelLocked();
- serviceIcon = mService.getServiceIconLocked();
+ if (mSessionFlags.mClientSuggestionsEnabled) {
+ final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
+ mService.getUserId());
+ targetLabel = ClientSuggestionsSession.getAppLabelLocked(
+ mService.getMaster().getContext(), appInfo);
+ targetIcon = ClientSuggestionsSession.getAppIconLocked(
+ mService.getMaster().getContext(), appInfo);
+ } else {
+ targetLabel = mService.getServiceLabelLocked();
+ targetIcon = mService.getServiceIconLocked();
+ }
}
- if (serviceLabel == null || serviceIcon == null) {
+ if (targetLabel == null || targetIcon == null) {
wtf(null, "onFillReady(): no service label or icon");
return;
}
@@ -3300,7 +3381,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mComponentName,
- serviceLabel, serviceIcon, this, id, mCompatMode);
+ targetLabel, targetIcon, this, id, mCompatMode);
synchronized (mLock) {
mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
@@ -3429,6 +3510,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return false;
}
+ final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
+ if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
+ || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
+ if (sDebug) {
+ Slog.d(TAG, "Inline suggestions not supported for "
+ + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
+ + ". Falling back to dropdown.");
+ }
+ return false;
+ }
+
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (remoteRenderService == null) {
@@ -3437,7 +3529,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
- new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
+ new InlineFillUi.InlineFillUiInfo(request, focusedId,
filterText, remoteRenderService, userId, id);
InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
new InlineFillUi.InlineSuggestionUiCallback() {
@@ -4051,6 +4143,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ @GuardedBy("mLock")
+ private void onClientFillRequestLocked(int requestId,
+ InlineSuggestionsRequest inlineSuggestionsRequest) {
+ if (mClientSuggestionsSession == null) {
+ mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
+ mComponentName, this);
+ }
+
+ if (mContexts == null) {
+ mContexts = new ArrayList<>(1);
+ }
+
+ if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
+ inlineSuggestionsRequest = null;
+ }
+
+ mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
+ }
+
/**
* The result of checking whether to show the save dialog, when session can be saved.
*
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index e80a6d9e0907..9f0deea503cf 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -235,60 +235,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
return;
}
- long homeVersion = 0;
- ArrayList<byte[]> homeSigHashes = null;
- PackageInfo homeInfo = null;
- String homeInstaller = null;
- ComponentName home = getPreferredHomeComponent();
- if (home != null) {
- try {
- homeInfo = mPackageManager.getPackageInfoAsUser(home.getPackageName(),
- PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
- homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
- homeVersion = homeInfo.getLongVersionCode();
- SigningInfo signingInfo = homeInfo.signingInfo;
- if (signingInfo == null) {
- Slog.e(TAG, "Home app has no signing information");
- } else {
- // retrieve the newest sigs to back up
- // TODO (b/73988180) use entire signing history in case of rollbacks
- Signature[] homeInfoSignatures = signingInfo.getApkContentsSigners();
- homeSigHashes = BackupUtils.hashSignatureArray(homeInfoSignatures);
- }
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Can't access preferred home info");
- // proceed as though there were no preferred home set
- home = null;
- }
- }
-
try {
- // We need to push a new preferred-home-app record if:
- // 1. the version of the home app has changed since our last backup;
- // 2. the home app [or absence] we now use differs from the prior state,
- // OR 3. it looks like we use the same home app + version as before, but
- // the signatures don't match so we treat them as different apps.
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
- || !Objects.equals(home, mStoredHomeComponent)
- || (home != null
- && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi));
- if (needHomeBackup) {
- if (DEBUG) {
- Slog.i(TAG, "Home preference changed; backing up new state " + home);
- }
- if (home != null) {
- outputBuffer.reset();
- outputBufferStream.writeUTF(home.flattenToString());
- outputBufferStream.writeLong(homeVersion);
- outputBufferStream.writeUTF(homeInstaller != null ? homeInstaller : "" );
- writeSignatureHashArray(outputBufferStream, homeSigHashes);
- writeEntity(data, DEFAULT_HOME_KEY, outputBuffer.toByteArray());
- } else {
- data.writeEntityHeader(DEFAULT_HOME_KEY, -1);
- }
- }
-
/*
* Global metadata:
*
@@ -403,7 +350,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
}
// Finally, write the new state blob -- just the list of all apps we handled
- writeStateFile(mAllPackages, home, homeVersion, homeSigHashes, newState);
+ writeStateFile(mAllPackages, newState);
}
private static void writeEntity(BackupDataOutput data, String key, byte[] bytes)
@@ -623,8 +570,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
}
// Util: write out our new backup state file
- private void writeStateFile(List<PackageInfo> pkgs, ComponentName preferredHome,
- long homeVersion, ArrayList<byte[]> homeSigHashes, ParcelFileDescriptor stateFile) {
+ private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
BufferedOutputStream outbuf = new BufferedOutputStream(outstream);
DataOutputStream out = new DataOutputStream(outbuf);
@@ -635,14 +581,6 @@ public class PackageManagerBackupAgent extends BackupAgent {
out.writeUTF(STATE_FILE_HEADER);
out.writeInt(STATE_FILE_VERSION);
- // If we remembered a preferred home app, record that
- if (preferredHome != null) {
- out.writeUTF(DEFAULT_HOME_KEY);
- out.writeUTF(preferredHome.flattenToString());
- out.writeLong(homeVersion);
- writeSignatureHashArray(out, homeSigHashes);
- }
-
// Conclude with the metadata block
out.writeUTF(GLOBAL_METADATA_KEY);
out.writeInt(Build.VERSION.SDK_INT);
@@ -789,6 +727,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
+ Build.VERSION.INCREMENTAL + ")");
}
} else if (key.equals(DEFAULT_HOME_KEY)) {
+ // Default home app data is no longer backed up by this agent. This code is
+ // kept to handle restore of old backups that still contain home app data.
String cn = inputBufferStream.readUTF();
mRestoredHome = ComponentName.unflattenFromString(cn);
mRestoredHomeVersion = inputBufferStream.readLong();
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index ca7fe0c571d1..243a7e0ed2ad 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -85,7 +85,6 @@ import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
import android.os.SELinux;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -3997,7 +3996,7 @@ public class UserBackupManagerService {
String callerLogString = "BMS.filterAppsEligibleForBackup";
TransportConnection transportConnection =
mTransportManager.getCurrentTransportClient(callerLogString);
- List<String> eligibleApps = new LinkedList<>();
+ List<String> eligibleApps = new ArrayList<>();
for (String packageName : packages) {
if (mScheduledBackupEligibility.appIsRunningAndEligibleForBackupWithTransport(
transportConnection, packageName)) {
@@ -4007,7 +4006,7 @@ public class UserBackupManagerService {
if (transportConnection != null) {
mTransportManager.disposeOfTransportClient(transportConnection, callerLogString);
}
- return eligibleApps.toArray(new String[eligibleApps.size()]);
+ return eligibleApps.toArray(new String[0]);
} finally {
Binder.restoreCallingIdentity(oldToken);
}
@@ -4155,6 +4154,24 @@ public class UserBackupManagerService {
pw.print(" : ");
pw.println(entry.packageName);
}
+ pw.println(userPrefix + "Agent timeouts:");
+ pw.println(" KvBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis());
+ pw.println(" FullBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis());
+ pw.println(" SharedBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis());
+ pw.println(" RestoreAgentTimeoutMillis (system): "
+ + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ Process.FIRST_APPLICATION_UID - 1));
+ pw.println(" RestoreAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ Process.FIRST_APPLICATION_UID));
+ pw.println(" RestoreAgentFinishedTimeoutMillis: "
+ + mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis());
+ pw.println(" QuotaExceededTimeoutMillis: "
+ + mAgentTimeoutParameters.getQuotaExceededTimeoutMillis());
+
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 76df8b9f84e8..e78c8d1ddcac 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -24,8 +24,10 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
+import android.annotation.NonNull;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupManager;
import android.app.backup.FullBackup;
import android.app.backup.IBackupManagerMonitor;
@@ -38,10 +40,12 @@ import android.content.pm.Signature;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.Settings;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.backup.BackupAgentTimeoutParameters;
import com.android.server.backup.BackupRestoreTask;
@@ -57,6 +61,7 @@ import com.android.server.backup.utils.FullBackupRestoreObserverUtils;
import com.android.server.backup.utils.RestoreUtils;
import com.android.server.backup.utils.TarBackupReader;
+import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -135,6 +140,8 @@ public class FullRestoreEngine extends RestoreEngine {
private boolean mPipesClosed;
private final BackupEligibilityRules mBackupEligibilityRules;
+ private FileMetadata mReadOnlyParent = null;
+
public FullRestoreEngine(
UserBackupManagerService backupManagerService, OperationStorage operationStorage,
BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
@@ -158,6 +165,22 @@ public class FullRestoreEngine extends RestoreEngine {
mBackupEligibilityRules = backupEligibilityRules;
}
+ @VisibleForTesting
+ FullRestoreEngine() {
+ mIsAdbRestore = false;
+ mAllowApks = false;
+ mEphemeralOpToken = 0;
+ mUserId = 0;
+ mBackupEligibilityRules = null;
+ mAgentTimeoutParameters = null;
+ mBuffer = null;
+ mBackupManagerService = null;
+ mOperationStorage = null;
+ mMonitor = null;
+ mMonitorTask = null;
+ mOnlyPackage = null;
+ }
+
public IBackupAgent getAgent() {
return mAgent;
}
@@ -397,6 +420,11 @@ public class FullRestoreEngine extends RestoreEngine {
okay = false;
}
+ if (shouldSkipReadOnlyDir(info)) {
+ // b/194894879: We don't support restore of read-only dirs.
+ okay = false;
+ }
+
// At this point we have an agent ready to handle the full
// restore data as well as a pipe for sending data to
// that agent. Tell the agent to start reading from the
@@ -573,6 +601,45 @@ public class FullRestoreEngine extends RestoreEngine {
return (info != null);
}
+ boolean shouldSkipReadOnlyDir(FileMetadata info) {
+ if (isValidParent(mReadOnlyParent, info)) {
+ // This file has a read-only parent directory, we shouldn't
+ // restore it.
+ return true;
+ } else {
+ // We're now in a different branch of the file tree, update the parent
+ // value.
+ if (isReadOnlyDir(info)) {
+ // Current directory is read-only. Remember it so that we can skip all
+ // of its contents.
+ mReadOnlyParent = info;
+ Slog.w(TAG, "Skipping restore of " + info.path + " and its contents as "
+ + "read-only dirs are currently not supported.");
+ return true;
+ } else {
+ mReadOnlyParent = null;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isValidParent(FileMetadata parentDir, @NonNull FileMetadata childDir) {
+ return parentDir != null
+ && childDir.packageName.equals(parentDir.packageName)
+ && childDir.domain.equals(parentDir.domain)
+ && childDir.path.startsWith(getPathWithTrailingSeparator(parentDir.path));
+ }
+
+ private static String getPathWithTrailingSeparator(String path) {
+ return path.endsWith(File.separator) ? path : path + File.separator;
+ }
+
+ private static boolean isReadOnlyDir(FileMetadata file) {
+ // Check if owner has 'write' bit in the file's mode value (see 'man -7 inode' for details).
+ return file.type == BackupAgent.TYPE_DIRECTORY && (file.mode & OsConstants.S_IWUSR) == 0;
+ }
+
private void setUpPipes() throws IOException {
synchronized (mPipesLock) {
mPipes = ParcelFileDescriptor.createPipe();
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index bd1ac2dcffda..5dacdb40713b 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -189,8 +189,9 @@ public class BackupEligibilityRules {
boolean isDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
if (UserHandle.isCore(app.uid) || isPrivileged) {
try {
- return mPackageManager.getProperty(PackageManager.PROPERTY_ALLOW_ADB_BACKUP,
- packageName).getBoolean();
+ return mPackageManager.getPropertyAsUser(
+ PackageManager.PROPERTY_ALLOW_ADB_BACKUP, packageName,
+ null /* className */, mUserId).getBoolean();
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Failed to read allowAdbBackup property for + "
+ packageName);
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 570e4e6fdc3d..5457ef9acaf7 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -26,6 +26,7 @@ import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature;
import static com.android.server.companion.PermissionsUtils.enforcePermissionsForAssociation;
import static com.android.server.companion.RolesUtils.isRoleHolder;
+import static com.android.server.companion.Utils.prepareForIpc;
import static java.util.Objects.requireNonNull;
@@ -47,7 +48,6 @@ import android.net.MacAddress;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
@@ -402,20 +402,4 @@ class AssociationRequestsProcessor {
return requestingPackageSignatureAllowlisted;
}
-
- /**
- * Convert an instance of a "locally-defined" ResultReceiver to an instance of
- * {@link android.os.ResultReceiver} itself, which the receiving process will be able to
- * unmarshall.
- */
- private static <T extends ResultReceiver> ResultReceiver prepareForIpc(T resultReceiver) {
- final Parcel parcel = Parcel.obtain();
- resultReceiver.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
-
- final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel);
- parcel.recycle();
-
- return ipcFriendly;
- }
}
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 64729a2553df..2ab1aa80176a 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -63,7 +63,7 @@ import java.util.Map;
* @see CompanionDeviceServiceConnector
*/
@SuppressLint("LongLogTag")
-class CompanionApplicationController {
+public class CompanionApplicationController {
static final boolean DEBUG = false;
private static final String TAG = "CompanionDevice_ApplicationController";
@@ -104,7 +104,10 @@ class CompanionApplicationController {
mCompanionServicesRegister.invalidate(userId);
}
- void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ /**
+ * CDM binds to the companion app.
+ */
+ public void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
boolean isSelfManaged) {
if (DEBUG) {
Log.i(TAG, "bind() u" + userId + "/" + packageName
@@ -144,7 +147,10 @@ class CompanionApplicationController {
}
}
- void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
+ /**
+ * CDM unbinds the companion app.
+ */
+ public void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
if (DEBUG) Log.i(TAG, "unbind() u" + userId + "/" + packageName);
final List<CompanionDeviceServiceConnector> serviceConnectors;
@@ -165,7 +171,10 @@ class CompanionApplicationController {
}
}
- boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) {
+ /**
+ * @return whether the companion application is bound now.
+ */
+ public boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) {
synchronized (mBoundCompanionApplications) {
return mBoundCompanionApplications.containsValueForPackage(userId, packageName);
}
@@ -235,6 +244,29 @@ class CompanionApplicationController {
primaryServiceConnector.postOnDeviceDisappeared(association);
}
+ /** Pass an encrypted secure message to the companion application for transporting. */
+ public void dispatchMessage(@UserIdInt int userId, @NonNull String packageName,
+ int associationId, int messageId, @NonNull byte[] message) {
+ if (DEBUG) {
+ Log.i(TAG, "dispatchMessage() u" + userId + "/" + packageName
+ + " associationId=" + associationId);
+ }
+
+ final CompanionDeviceServiceConnector primaryServiceConnector =
+ getPrimaryServiceConnector(userId, packageName);
+ if (primaryServiceConnector == null) {
+ if (DEBUG) {
+ Log.e(TAG, "dispatchMessage(): "
+ + "u" + userId + "/" + packageName + " is NOT bound.");
+ Log.d(TAG, "Stacktrace", new Throwable());
+ }
+ return;
+ }
+
+ primaryServiceConnector.postOnMessageDispatchedFromSystem(associationId, messageId,
+ message);
+ }
+
void dump(@NonNull PrintWriter out) {
out.append("Companion Device Application Controller: \n");
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 3f7cba6a4d09..beea374bacc7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -82,6 +82,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
+import android.util.Base64;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.Slog;
@@ -98,7 +99,11 @@ import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.companion.datatransfer.CompanionMessageProcessor;
+import com.android.server.companion.datatransfer.SystemDataTransferProcessor;
+import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager;
import com.android.server.pm.UserManagerInternal;
import java.io.File;
@@ -131,9 +136,13 @@ public class CompanionDeviceManagerService extends SystemService {
private final PersistUserStateHandler mUserPersistenceHandler;
private final AssociationStoreImpl mAssociationStore;
+ private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
private AssociationRequestsProcessor mAssociationRequestsProcessor;
+ private SystemDataTransferProcessor mSystemDataTransferProcessor;
+ private CompanionMessageProcessor mCompanionMessageProcessor;
private CompanionDevicePresenceMonitor mDevicePresenceMonitor;
private CompanionApplicationController mCompanionAppController;
+ private CompanionSecureCommunicationsManager mSecureCommsManager;
private final ActivityManagerInternal mAmInternal;
private final IAppOpsService mAppOpsManager;
@@ -165,10 +174,13 @@ public class CompanionDeviceManagerService extends SystemService {
mUserPersistenceHandler = new PersistUserStateHandler();
mAssociationStore = new AssociationStoreImpl();
+ mSystemDataTransferRequestStore = new SystemDataTransferRequestStore();
}
@Override
public void onStart() {
+ final Context context = getContext();
+
mPersistentStore = new PersistentDataStore();
loadAssociationsFromDisk();
@@ -179,10 +191,13 @@ public class CompanionDeviceManagerService extends SystemService {
mAssociationRequestsProcessor = new AssociationRequestsProcessor(
/* cdmService */this, mAssociationStore);
-
- final Context context = getContext();
mCompanionAppController = new CompanionApplicationController(
context, mApplicationControllerCallback);
+ mSecureCommsManager = new CompanionSecureCommunicationsManager(
+ mAssociationStore, mCompanionAppController);
+ mCompanionMessageProcessor = new CompanionMessageProcessor(mSecureCommsManager);
+ mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore,
+ mSystemDataTransferRequestStore, mCompanionMessageProcessor);
// Publish "binder" service.
final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl();
@@ -251,7 +266,7 @@ public class CompanionDeviceManagerService extends SystemService {
if (DEBUG) Log.i(TAG, "onDevice_Appeared_Internal() id=" + associationId);
final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (DEBUG) Log.d(TAG, " association=" + associationId);
+ if (DEBUG) Log.d(TAG, " association=" + association);
if (!association.shouldBindWhenPresent()) return;
@@ -273,7 +288,7 @@ public class CompanionDeviceManagerService extends SystemService {
if (DEBUG) Log.i(TAG, "onDevice_Disappeared_Internal() id=" + associationId);
final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (DEBUG) Log.d(TAG, " association=" + associationId);
+ if (DEBUG) Log.d(TAG, " association=" + association);
final int userId = association.getUserId();
final String packageName = association.getPackageName();
@@ -600,9 +615,34 @@ public class CompanionDeviceManagerService extends SystemService {
}
@Override
- public void dispatchMessage(int messageId, int associationId, byte[] message)
- throws RemoteException {
- // TODO(b/199427116): implement.
+ public void dispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+ if (DEBUG) {
+ Log.i(TAG, "dispatchMessage() associationId=" + associationId + "\n"
+ + " message(Base64)=" + Base64.encodeToString(message, 0));
+ }
+
+ AssociationInfo association = getAssociationWithCallerChecks(associationId);
+ if (association == null) {
+ throw new IllegalArgumentException("Association with ID " + associationId + " "
+ + "does not exist "
+ + "or belongs to a different package "
+ + "or belongs to a different user");
+ }
+
+ mSecureCommsManager.receiveSecureMessage(messageId, associationId, message);
+ }
+
+ @Override
+ public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,
+ int userId, int associationId) {
+ return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent(
+ packageName, userId, associationId);
+ }
+
+ @Override
+ public void startSystemDataTransfer(String packageName, int userId, int associationId) {
+ mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId,
+ associationId);
}
@Override
@@ -749,10 +789,10 @@ public class CompanionDeviceManagerService extends SystemService {
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
-
final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
CompanionDeviceManagerService.this,
mAssociationStore,
+ mSecureCommsManager,
mDevicePresenceMonitor);
cmd.exec(this, in, out, err, args, callback, resultReceiver);
}
@@ -887,6 +927,9 @@ public class CompanionDeviceManagerService extends SystemService {
mAssociationStore.removeAssociation(associationId);
logRemoveAssociation(deviceProfile);
+ // Remove all the system data transfer requests for the association.
+ mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
+
final List<AssociationInfo> otherAssociations =
mAssociationStore.getAssociationsForPackage(userId, packageName);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index a288f7b2993c..7360f0846ed3 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -99,6 +99,12 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
post(companionService -> companionService.onDeviceDisappeared(associationInfo));
}
+ void postOnMessageDispatchedFromSystem(int associationId, int messageId,
+ @NonNull byte[] message) {
+ post(companionService ->
+ companionService.onMessageDispatchedFromSystem(messageId, associationId, message));
+ }
+
/**
* Post "unbind" job, which will run *after* all previously posted jobs complete.
*
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 434d283b3f8a..0b7bc03eebba 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -16,11 +16,14 @@
package com.android.server.companion;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import android.companion.AssociationInfo;
import android.os.Binder;
import android.os.ShellCommand;
-import android.util.Log;
-import android.util.Slog;
+import android.util.Base64;
+
+import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
@@ -32,13 +35,16 @@ class CompanionDeviceShellCommand extends ShellCommand {
private final CompanionDeviceManagerService mService;
private final AssociationStore mAssociationStore;
+ private final CompanionSecureCommunicationsManager mSecureCommsManager;
private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
AssociationStore associationStore,
+ CompanionSecureCommunicationsManager secureCommsManager,
CompanionDevicePresenceMonitor devicePresenceMonitor) {
mService = service;
mAssociationStore = associationStore;
+ mSecureCommsManager = secureCommsManager;
mDevicePresenceMonitor = devicePresenceMonitor;
}
@@ -81,11 +87,36 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
break;
- case "clear-association-memory-cache": {
+ case "clear-association-memory-cache":
mService.persistState();
mService.loadAssociationsFromDisk();
- }
- break;
+ break;
+
+ case "send-secure-message":
+ associationId = getNextIntArgRequired();
+ final byte[] message;
+
+ // The message should be either a UTF-8 String or Base64-encoded data.
+ final boolean isBase64 = "--base64".equals(getNextOption());
+ if (isBase64) {
+ final String base64encodedMessage = getNextArgRequired();
+ message = Base64.decode(base64encodedMessage, 0);
+ } else {
+ // We treat the rest of the command as the message, which should contain at
+ // least one word (hence getNextArg_Required() below), but there may be
+ // more.
+ final StringBuilder sb = new StringBuilder(getNextArgRequired());
+ // Pick up the rest.
+ for (String word : peekRemainingArgs()) {
+ sb.append(" ").append(word);
+ }
+ // And now convert to byte[]...
+ message = sb.toString().getBytes(UTF_8);
+ }
+
+ mSecureCommsManager.sendSecureMessage(associationId, /* messageId */ 0,
+ message);
+ break;
case "simulate-device-appeared":
associationId = getNextIntArgRequired();
@@ -110,12 +141,18 @@ class CompanionDeviceShellCommand extends ShellCommand {
default:
return handleDefaultCommands(cmd);
}
- return 0;
- } catch (Throwable t) {
- Slog.e(TAG, "Error running a command: $ " + cmd, t);
- getErrPrintWriter().println(Log.getStackTraceString(t));
+ } catch (Throwable e) {
+ final PrintWriter errOut = getErrPrintWriter();
+ errOut.println();
+ errOut.println("Exception occurred while executing '" + cmd + "':");
+ e.printStackTrace(errOut);
return 1;
}
+ return 0;
+ }
+
+ private int getNextIntArgRequired() {
+ return Integer.parseInt(getNextArgRequired());
}
@Override
@@ -130,6 +167,8 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" Create a new Association.");
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
+ pw.println(" send-secure-message ASSOCIATION_ID [--base64] MESSAGE");
+ pw.println(" Send a secure message to an associated companion device.");
pw.println(" clear-association-memory-cache");
pw.println(" Clear the in-memory association cache and reload all association ");
pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
@@ -160,8 +199,4 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" \"debug.cdm.cdmservice.cleanup_time_window\" system property). ");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
}
-
- private int getNextIntArgRequired() {
- return Integer.parseInt(getNextArgRequired());
- }
}
diff --git a/services/companion/java/com/android/server/companion/DataStoreUtils.java b/services/companion/java/com/android/server/companion/DataStoreUtils.java
index 8ac741a44ee5..73e68ec0bf97 100644
--- a/services/companion/java/com/android/server/companion/DataStoreUtils.java
+++ b/services/companion/java/com/android/server/companion/DataStoreUtils.java
@@ -33,15 +33,24 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileOutputStream;
-final class DataStoreUtils {
+/**
+ * Util class for CDM data stores
+ */
+public final class DataStoreUtils {
private static final String TAG = "CompanionDevice_DataStoreUtils";
- static boolean isStartOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
+ /**
+ * Check if the parser pointer is at the start of the tag
+ */
+ public static boolean isStartOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
throws XmlPullParserException {
return parser.getEventType() == START_TAG && tag.equals(parser.getName());
}
- static boolean isEndOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
+ /**
+ * Check if the parser pointer is at the end of the tag
+ */
+ public static boolean isEndOfTag(@NonNull XmlPullParser parser, @NonNull String tag)
throws XmlPullParserException {
return parser.getEventType() == END_TAG && tag.equals(parser.getName());
}
@@ -57,7 +66,7 @@ final class DataStoreUtils {
* @return an AtomicFile for the user
*/
@NonNull
- static AtomicFile createStorageFileForUser(@UserIdInt int userId, String fileName) {
+ public static AtomicFile createStorageFileForUser(@UserIdInt int userId, String fileName) {
return new AtomicFile(getBaseStorageFileForUser(userId, fileName));
}
@@ -70,7 +79,7 @@ final class DataStoreUtils {
* Writing to file could fail, for example, if the user has been recently removed and so was
* their DE (/data/system_de/<user-id>/) directory.
*/
- static void writeToFileSafely(
+ public static void writeToFileSafely(
@NonNull AtomicFile file, @NonNull ThrowingConsumer<FileOutputStream> consumer) {
try {
file.write(consumer);
diff --git a/services/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/PackageUtils.java
index a2b20593a9cb..622396ccfa36 100644
--- a/services/companion/java/com/android/server/companion/PackageUtils.java
+++ b/services/companion/java/com/android/server/companion/PackageUtils.java
@@ -41,8 +41,8 @@ import android.util.Slog;
import com.android.internal.util.ArrayUtils;
+import java.util.ArrayList;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -87,7 +87,8 @@ final class PackageUtils {
final List<ResolveInfo> companionServices = pm.queryIntentServicesAsUser(
COMPANION_SERVICE_INTENT, ResolveInfoFlags.of(0), userId);
- final Map<String, List<ComponentName>> packageNameToServiceInfoList = new HashMap<>();
+ final Map<String, List<ComponentName>> packageNameToServiceInfoList =
+ new HashMap<>(companionServices.size());
for (ResolveInfo resolveInfo : companionServices) {
final ServiceInfo service = resolveInfo.serviceInfo;
@@ -101,19 +102,19 @@ final class PackageUtils {
continue;
}
- // Use LinkedList, because we'll need to prepend "primary" services, while appending the
- // other (non-primary) services to the list.
- final LinkedList<ComponentName> services =
- (LinkedList<ComponentName>) packageNameToServiceInfoList.computeIfAbsent(
- service.packageName, it -> new LinkedList<>());
+ // We'll need to prepend "primary" services, while appending the other (non-primary)
+ // services to the list.
+ final ArrayList<ComponentName> services =
+ (ArrayList<ComponentName>) packageNameToServiceInfoList.computeIfAbsent(
+ service.packageName, it -> new ArrayList<>(1));
final ComponentName componentName = service.getComponentName();
- if (isPrimaryCompanionDeviceService(pm, componentName)) {
+ if (isPrimaryCompanionDeviceService(pm, componentName, userId)) {
// "Primary" service should be at the head of the list.
- services.addFirst(componentName);
+ services.add(0, componentName);
} else {
- services.addLast(componentName);
+ services.add(componentName);
}
}
@@ -121,9 +122,10 @@ final class PackageUtils {
}
private static boolean isPrimaryCompanionDeviceService(@NonNull PackageManager pm,
- @NonNull ComponentName componentName) {
+ @NonNull ComponentName componentName, @UserIdInt int userId) {
try {
- return pm.getProperty(PROPERTY_PRIMARY_TAG, componentName).getBoolean();
+ return pm.getPropertyAsUser(PROPERTY_PRIMARY_TAG, componentName.getPackageName(),
+ componentName.getClassName(), userId).getBoolean();
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java
index ac1bf1bd8c23..a41ac03d4513 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java
@@ -54,7 +54,7 @@ import java.util.Map;
* {@link Manifest.permission#REQUEST_COMPANION_PROFILE_APP_STREAMING},
* {@link Manifest.permission#REQUEST_COMPANION_SELF_MANAGED} etc.)
*/
-final class PermissionsUtils {
+public final class PermissionsUtils {
private static final Map<String, String> DEVICE_PROFILE_TO_PERMISSION;
static {
@@ -132,7 +132,11 @@ final class PermissionsUtils {
return true;
}
- static void enforceCallerIsSystemOr(@UserIdInt int userId, @NonNull String packageName) {
+ /**
+ * Check if the calling user id matches the userId, and if the package belongs to
+ * the calling uid.
+ */
+ public static void enforceCallerIsSystemOr(@UserIdInt int userId, @NonNull String packageName) {
final int callingUid = getCallingUid();
if (callingUid == SYSTEM_UID) return;
@@ -191,7 +195,11 @@ final class PermissionsUtils {
return checkCallerCanManageCompanionDevice(context);
}
- static @Nullable AssociationInfo sanitizeWithCallerChecks(@NonNull Context context,
+ /**
+ * Check if CDM can trust the context to process the association.
+ */
+ @Nullable
+ public static AssociationInfo sanitizeWithCallerChecks(@NonNull Context context,
@Nullable AssociationInfo association) {
if (association == null) return null;
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 36393894f727..4d42838fff50 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -103,7 +103,7 @@ import java.util.concurrent.ConcurrentMap;
* Since Android T the data is stored to "companion_device_manager.xml" file in
* {@link Environment#getDataSystemDeDirectory(int) /data/system_de/}.
*
- * See {@link #getBaseStorageFileForUser(int) getBaseStorageFileForUser()}
+ * See {@link #getStorageFileForUser(int)}
*
* <p>
* Since Android T the data is stored using the v1 schema.
diff --git a/services/companion/java/com/android/server/companion/Utils.java b/services/companion/java/com/android/server/companion/Utils.java
new file mode 100644
index 000000000000..b9f61ecd8c4f
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/Utils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 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.companion;
+
+import android.os.Parcel;
+import android.os.ResultReceiver;
+
+/**
+ * A miscellaneous util class for CDM
+ *
+ * @hide
+ */
+public final class Utils {
+
+ /**
+ * Convert an instance of a "locally-defined" ResultReceiver to an instance of
+ * {@link android.os.ResultReceiver} itself, which the receiving process will be able to
+ * unmarshall.
+ * @hide
+ */
+ public static <T extends ResultReceiver> ResultReceiver prepareForIpc(T resultReceiver) {
+ final Parcel parcel = Parcel.obtain();
+ resultReceiver.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ return ipcFriendly;
+ }
+
+ private Utils() {}
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageInfo.java b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageInfo.java
new file mode 100644
index 000000000000..91ad93c98240
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageInfo.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer;
+
+class CompanionMessageInfo {
+
+ private final long mId;
+ private final int mPage;
+ private final int mTotal;
+ private final int mType;
+ private final byte[] mData;
+
+ CompanionMessageInfo(long id, int page, int total, int type, byte[] data) {
+ mId = id;
+ mPage = page;
+ mTotal = total;
+ mType = type;
+ mData = data;
+ }
+
+ public long getId() {
+ return mId;
+ }
+
+ public int getPage() {
+ return mPage;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public byte[] getData() {
+ return mData;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java
new file mode 100644
index 000000000000..98a00aa6fadc
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/CompanionMessageProcessor.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.companion.proto.CompanionMessage;
+import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class builds and reads CompanionMessage. And also paginate and combine messages.
+ */
+public class CompanionMessageProcessor {
+
+ private static final String LOG_TAG = CompanionMessageProcessor.class.getSimpleName();
+
+ /** Listener for incoming complete messages. */
+ interface Listener {
+ /** When a complete message is received from the companion app. */
+ void onCompleteMessageReceived(@NonNull CompanionMessageInfo message);
+ }
+
+ // Rough size for each CompanionMessage, each message can exceed 50K for a little, but not
+ // too much. Hard limit is 100K, WCS data processing limit. Closer to 100K, less stable at
+ // the WCS data processing layer. Refer to
+ // https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageClient
+ // #public-abstract-taskinteger-sendmessage-string-nodeid,-string-path,-byte[]-data
+ private static final int MESSAGE_SIZE_IN_BYTES = 50000;
+
+ private final CompanionSecureCommunicationsManager mSecureCommsManager;
+
+ @Nullable
+ private Listener mListener;
+
+ // Association id -> (parent id -> received messages)
+ private final Map<Integer, Map<Integer, List<CompanionMessageInfo>>> mAssociationsMessagesMap =
+ new HashMap<>();
+ // Association id -> next parent id
+ private final Map<Integer, Integer> mNextParentId = new HashMap<>();
+
+ public CompanionMessageProcessor(CompanionSecureCommunicationsManager secureCommsManager) {
+ mSecureCommsManager = secureCommsManager;
+ mSecureCommsManager.setListener(this::onDecryptedMessageReceived);
+ }
+
+ public void setListener(@NonNull Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Paginate the data into multiple messages with size limit. And dispatch the messages to the
+ * companion app.
+ */
+ public void paginateAndDispatchMessagesToApp(byte[] data, int messageType,
+ String packageName, int userId, int associationId) {
+ Slog.i(LOG_TAG, "Paginating " + data.length + " bytes.");
+
+ final int totalMessageCount = (data.length / MESSAGE_SIZE_IN_BYTES)
+ + ((data.length % MESSAGE_SIZE_IN_BYTES == 0) ? 0 : 1);
+ int parentMessageId = findNextParentId(associationId, totalMessageCount);
+
+ for (int i = 0; i < totalMessageCount; i++) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ int messageId = parentMessageId + i + 1;
+ proto.write(CompanionMessage.ID, messageId);
+
+ long paginationInfoToken = proto.start(CompanionMessage.PAGINATION_INFO);
+ proto.write(CompanionMessage.PaginationInfo.PARENT_ID, parentMessageId);
+ proto.write(CompanionMessage.PaginationInfo.PAGE, i + 1);
+ proto.write(CompanionMessage.PaginationInfo.TOTAL, totalMessageCount);
+ proto.end(paginationInfoToken);
+
+ proto.write(CompanionMessage.TYPE, messageType);
+ byte[] currentData = Arrays.copyOfRange(data, i * MESSAGE_SIZE_IN_BYTES,
+ Math.min((i + 1) * MESSAGE_SIZE_IN_BYTES, data.length));
+ proto.write(CompanionMessage.DATA, currentData);
+
+ byte[] message = proto.getBytes();
+
+ Slog.i(LOG_TAG, "Sending [" + message.length + "] bytes to " + packageName);
+
+ mSecureCommsManager.sendSecureMessage(associationId, messageId, message);
+ }
+ }
+
+ /**
+ * Process the message and store it. If all the messages with the same parent id have been
+ * received, return the message with combined message data. Otherwise, return null if there's
+ * still data parts missing.
+ */
+ public CompanionMessageInfo onDecryptedMessageReceived(int messageId, int associationId,
+ byte[] message) {
+ Slog.i(LOG_TAG, "Partial message received, size [" + message.length
+ + "], reading from protobuf.");
+
+ ProtoInputStream proto = new ProtoInputStream(message);
+ try {
+ int id = 0;
+ int parentId = 0;
+ int page = 0;
+ int total = 0;
+ int type = CompanionMessage.UNKNOWN;
+ byte[] data = null;
+
+ // Read proto data
+ while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (proto.getFieldNumber()) {
+ case (int) CompanionMessage.ID:
+ id = proto.readInt(CompanionMessage.ID);
+ break;
+ case (int) CompanionMessage.PAGINATION_INFO:
+ long paginationToken = proto.start(CompanionMessage.PAGINATION_INFO);
+ while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (proto.getFieldNumber()) {
+ case (int) CompanionMessage.PaginationInfo.PARENT_ID:
+ parentId = proto.readInt(
+ CompanionMessage.PaginationInfo.PARENT_ID);
+ break;
+ case (int) CompanionMessage.PaginationInfo.PAGE:
+ page = proto.readInt(CompanionMessage.PaginationInfo.PAGE);
+ break;
+ case (int) CompanionMessage.PaginationInfo.TOTAL:
+ total = proto.readInt(CompanionMessage.PaginationInfo.TOTAL);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unexpected field id "
+ + proto.getFieldNumber() + " for PaginationInfo.");
+ break;
+ }
+ }
+ proto.end(paginationToken);
+ break;
+ case (int) CompanionMessage.TYPE:
+ type = proto.readInt(CompanionMessage.TYPE);
+ break;
+ case (int) CompanionMessage.DATA:
+ data = proto.readBytes(CompanionMessage.DATA);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unexpected field id " + proto.getFieldNumber()
+ + " for CompanionMessage.");
+ break;
+ }
+ }
+
+ if (id == messageId) {
+ CompanionMessageInfo messageInfo = new CompanionMessageInfo(id, page, total, type,
+ data);
+ // Add the message into mAssociationsMessagesMap
+ Map<Integer, List<CompanionMessageInfo>> associationMessages =
+ mAssociationsMessagesMap.getOrDefault(associationId, new HashMap<>());
+ List<CompanionMessageInfo> childMessages = associationMessages.getOrDefault(
+ parentId, new ArrayList<>());
+ childMessages.add(messageInfo);
+ associationMessages.put(parentId, childMessages);
+ mAssociationsMessagesMap.put(associationId, associationMessages);
+ // Check if all the messages with the same parentId are received.
+ if (childMessages.size() == total) {
+ Slog.i(LOG_TAG, "All [" + total + "] messages are received for parentId ["
+ + parentId + "]. Processing.");
+
+ childMessages.sort(Comparator.comparing(CompanionMessageInfo::getPage));
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ for (int i = 0; i < childMessages.size(); i++) {
+ stream.write(childMessages.get(i).getData());
+ }
+ mAssociationsMessagesMap.remove(parentId);
+ mListener.onCompleteMessageReceived(
+ new CompanionMessageInfo(parentId, 0, total, type,
+ stream.toByteArray()));
+ } else {
+ Slog.i(LOG_TAG, "[" + childMessages.size() + "/" + total
+ + "] messages are received for parentId [" + parentId + "]");
+ }
+ } else {
+ Slog.e(LOG_TAG, "Message id mismatch.");
+ return null;
+ }
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "Can't read proto from the message.");
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Find the next parent id from [1, Integer.MAX_VALUE].
+ * The parent and child ids are incremental.
+ */
+ private int findNextParentId(int associationId, int totalMessageCount) {
+ int nextParentId = mNextParentId.getOrDefault(associationId, 1);
+
+ // If the last child message id exceeds the Integer range, start from 1 again.
+ if (nextParentId > Integer.MAX_VALUE - totalMessageCount - 1) {
+ nextParentId = 1;
+ }
+
+ mNextParentId.put(associationId, nextParentId + totalMessageCount + 1);
+
+ return nextParentId;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
new file mode 100644
index 000000000000..395cf1805b63
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer;
+
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME;
+import static android.content.ComponentName.createRelative;
+
+import static com.android.server.companion.Utils.prepareForIpc;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.PendingIntent;
+import android.companion.AssociationInfo;
+import android.companion.DeviceNotAssociatedException;
+import android.companion.datatransfer.PermissionSyncRequest;
+import android.companion.datatransfer.SystemDataTransferRequest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.server.companion.AssociationStore;
+import com.android.server.companion.CompanionDeviceManagerService;
+import com.android.server.companion.PermissionsUtils;
+import com.android.server.companion.datatransfer.permbackup.BackupHelper;
+import com.android.server.companion.proto.CompanionMessage;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This processor builds user consent intent for a given SystemDataTransferRequest and processes the
+ * request when the system is ready (a secure channel is established between the handhold and the
+ * companion device).
+ */
+public class SystemDataTransferProcessor {
+
+ private static final String LOG_TAG = SystemDataTransferProcessor.class.getSimpleName();
+
+ // Values from UI to SystemDataTransferProcessor via ResultReceiver
+ private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED = 0;
+ private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_DISALLOWED = 1;
+ private static final String EXTRA_PERMISSION_SYNC_REQUEST = "permission_sync_request";
+ private static final String EXTRA_COMPANION_DEVICE_NAME = "companion_device_name";
+ private static final String EXTRA_SYSTEM_DATA_TRANSFER_RESULT_RECEIVER =
+ "system_data_transfer_result_receiver";
+ private static final ComponentName SYSTEM_DATA_TRANSFER_REQUEST_APPROVAL_ACTIVITY =
+ createRelative(COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
+ ".CompanionDeviceDataTransferActivity");
+
+ private final Context mContext;
+ private final AssociationStore mAssociationStore;
+ private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+ private final CompanionMessageProcessor mCompanionMessageProcessor;
+
+ public SystemDataTransferProcessor(CompanionDeviceManagerService service,
+ AssociationStore associationStore,
+ SystemDataTransferRequestStore systemDataTransferRequestStore,
+ CompanionMessageProcessor companionMessageProcessor) {
+ mContext = service.getContext();
+ mAssociationStore = associationStore;
+ mSystemDataTransferRequestStore = systemDataTransferRequestStore;
+ mCompanionMessageProcessor = companionMessageProcessor;
+ mCompanionMessageProcessor.setListener(this::onCompleteMessageReceived);
+ }
+
+ /**
+ * Build a PendingIntent of permission sync user consent dialog
+ */
+ public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,
+ @UserIdInt int userId, int associationId) {
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association);
+ if (association == null) {
+ throw new DeviceNotAssociatedException("Association "
+ + associationId + " is not associated with the app " + packageName
+ + " for user " + userId);
+ }
+
+ // Check if the request's data type has been requested before.
+ List<SystemDataTransferRequest> storedRequests =
+ mSystemDataTransferRequestStore.readRequestsByAssociationId(userId,
+ associationId);
+ for (SystemDataTransferRequest storedRequest : storedRequests) {
+ if (storedRequest instanceof PermissionSyncRequest) {
+ Slog.e(LOG_TAG, "The request has been sent before, you can not send "
+ + "the same request type again.");
+ return null;
+ }
+ }
+
+ Slog.i(LOG_TAG, "Creating permission sync intent for userId [" + userId
+ + "] associationId [" + associationId + "]");
+
+ // Create an internal intent to launch the user consent dialog
+ final Bundle extras = new Bundle();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserId(userId);
+ extras.putParcelable(EXTRA_PERMISSION_SYNC_REQUEST, request);
+ extras.putCharSequence(EXTRA_COMPANION_DEVICE_NAME, association.getDisplayName());
+ extras.putParcelable(EXTRA_SYSTEM_DATA_TRANSFER_RESULT_RECEIVER,
+ prepareForIpc(mOnSystemDataTransferRequestConfirmationReceiver));
+
+ final Intent intent = new Intent();
+ intent.setComponent(SYSTEM_DATA_TRANSFER_REQUEST_APPROVAL_ACTIVITY);
+ intent.putExtras(extras);
+
+ // Create a PendingIntent
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return PendingIntent.getActivity(mContext, /*requestCode */ associationId, intent,
+ FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Start system data transfer. It should first try to establish a secure channel and then sync
+ * system data.
+ */
+ public void startSystemDataTransfer(String packageName, int userId, int associationId) {
+ Slog.i(LOG_TAG, "Start system data transfer for package [" + packageName
+ + "] userId [" + userId + "] associationId [" + associationId + "]");
+
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association);
+ if (association == null) {
+ throw new DeviceNotAssociatedException("Association "
+ + associationId + " is not associated with the app " + packageName
+ + " for user " + userId);
+ }
+
+ // Check if the request has been consented by the user.
+ List<SystemDataTransferRequest> storedRequests =
+ mSystemDataTransferRequestStore.readRequestsByAssociationId(userId,
+ associationId);
+ boolean hasConsented = false;
+ for (SystemDataTransferRequest storedRequest : storedRequests) {
+ if (storedRequest instanceof PermissionSyncRequest && storedRequest.isUserConsented()) {
+ hasConsented = true;
+ break;
+ }
+ }
+ if (!hasConsented) {
+ Slog.e(LOG_TAG, "User " + userId + " hasn't consented permission sync.");
+ return;
+ }
+
+ // TODO: Establish a secure channel
+
+ final long callingIdentityToken = Binder.clearCallingIdentity();
+
+ // Start permission sync
+ try {
+ BackupHelper backupHelper = new BackupHelper(mContext, UserHandle.of(userId));
+ XmlSerializer serializer = Xml.newSerializer();
+ ByteArrayOutputStream backup = new ByteArrayOutputStream();
+ serializer.setOutput(backup, UTF_8.name());
+
+ backupHelper.writeState(serializer);
+
+ serializer.flush();
+
+ mCompanionMessageProcessor.paginateAndDispatchMessagesToApp(backup.toByteArray(),
+ CompanionMessage.PERMISSION_SYNC, packageName, userId, associationId);
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "Error while writing permission state.");
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentityToken);
+ }
+ }
+
+ /**
+ * Process a complete decrypted message reported by the companion app.
+ */
+ public void onCompleteMessageReceived(@NonNull CompanionMessageInfo completeMessage) {
+ switch (completeMessage.getType()) {
+ case CompanionMessage.PERMISSION_SYNC:
+ processPermissionSyncMessage(completeMessage);
+ break;
+ default:
+ Slog.e(LOG_TAG, "Unknown message type [" + completeMessage.getType()
+ + "]. Unable to process.");
+ }
+ }
+
+ private void processPermissionSyncMessage(CompanionMessageInfo messageInfo) {
+ Slog.i(LOG_TAG, "Applying permissions.");
+ // Start applying permissions
+ final long callingIdentityToken = Binder.clearCallingIdentity();
+ try {
+ BackupHelper backupHelper = new BackupHelper(mContext, mContext.getUser());
+ XmlPullParser parser = Xml.newPullParser();
+ ByteArrayInputStream stream = new ByteArrayInputStream(
+ messageInfo.getData());
+ parser.setInput(stream, UTF_8.name());
+
+ backupHelper.restoreState(parser);
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "IOException reading message: "
+ + new String(messageInfo.getData()));
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Error parsing message: "
+ + new String(messageInfo.getData()));
+ } finally {
+ Slog.i(LOG_TAG, "Permissions applied.");
+ Binder.restoreCallingIdentity(callingIdentityToken);
+ }
+ }
+
+ private final ResultReceiver mOnSystemDataTransferRequestConfirmationReceiver =
+ new ResultReceiver(Handler.getMain()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle data) {
+ Slog.d(LOG_TAG, "onReceiveResult() code=" + resultCode + ", "
+ + "data=" + data);
+
+ if (resultCode == RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED
+ || resultCode == RESULT_CODE_SYSTEM_DATA_TRANSFER_DISALLOWED) {
+ final PermissionSyncRequest request =
+ data.getParcelable(EXTRA_PERMISSION_SYNC_REQUEST,
+ PermissionSyncRequest.class);
+ if (request != null) {
+ request.setUserConsented(
+ resultCode == RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED);
+ Slog.i(LOG_TAG, "Recording request: " + request);
+ mSystemDataTransferRequestStore.writeRequest(request.getUserId(),
+ request);
+ }
+
+ return;
+ }
+
+ Slog.e(LOG_TAG, "Unknown result code:" + resultCode);
+ }
+ };
+}
diff --git a/services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index 38e5d16842b9..ab0a06260cfc 100644
--- a/services/companion/java/com/android/server/companion/SystemDataTransferRequestDataStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.companion;
+package com.android.server.companion.datatransfer;
+
+import static android.companion.datatransfer.SystemDataTransferRequest.DATA_TYPE_PERMISSION_SYNC;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readThisListXml;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeListXml;
import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
import static com.android.server.companion.DataStoreUtils.isEndOfTag;
import static com.android.server.companion.DataStoreUtils.isStartOfTag;
@@ -30,13 +30,16 @@ import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.companion.SystemDataTransferRequest;
+import android.companion.datatransfer.PermissionSyncRequest;
+import android.companion.datatransfer.SystemDataTransferRequest;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,46 +48,130 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* The class is responsible for reading/writing SystemDataTransferRequest records from/to the disk.
- *
+ * <p>
* The following snippet is a sample XML file stored in the disk.
* <pre>{@code
* <requests>
* <request
* association_id="1"
- * is_permission_sync_all_packages="false">
- * <list name="permission_sync_packages">
- * <string>com.sample.app1</string>
- * <string>com.sample.app2</string>
- * </list>
+ * data_type="1"
+ * user_id="12"
+ * is_user_consented="true"
* </request>
* </requests>
* }</pre>
*/
-public class SystemDataTransferRequestDataStore {
+public class SystemDataTransferRequestStore {
- private static final String LOG_TAG = SystemDataTransferRequestDataStore.class.getSimpleName();
+ private static final String LOG_TAG = SystemDataTransferRequestStore.class.getSimpleName();
private static final String FILE_NAME = "companion_device_system_data_transfer_requests.xml";
private static final String XML_TAG_REQUESTS = "requests";
private static final String XML_TAG_REQUEST = "request";
- private static final String XML_TAG_LIST = "list";
private static final String XML_ATTR_ASSOCIATION_ID = "association_id";
- private static final String XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES =
- "is_permission_sync_all_packages";
- private static final String XML_ATTR_PERMISSION_SYNC_PACKAGES = "permission_sync_packages";
+ private static final String XML_ATTR_DATA_TYPE = "data_type";
+ private static final String XML_ATTR_USER_ID = "user_id";
+ private static final String XML_ATTR_IS_USER_CONSENTED = "is_user_consented";
+
+ private static final int READ_FROM_DISK_TIMEOUT = 5; // in seconds
+ private final ExecutorService mExecutor;
private final ConcurrentMap<Integer, AtomicFile> mUserIdToStorageFile =
new ConcurrentHashMap<>();
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final SparseArray<ArrayList<SystemDataTransferRequest>> mCachedPerUser =
+ new SparseArray<>();
+
+ public SystemDataTransferRequestStore() {
+ mExecutor = Executors.newSingleThreadExecutor();
+ }
+
+ @NonNull
+ List<SystemDataTransferRequest> readRequestsByAssociationId(@UserIdInt int userId,
+ int associationId) {
+ List<SystemDataTransferRequest> cachedRequests;
+ synchronized (mLock) {
+ cachedRequests = readRequestsFromCache(userId);
+ }
+
+ List<SystemDataTransferRequest> requestsByAssociationId = new ArrayList<>();
+ for (SystemDataTransferRequest request : cachedRequests) {
+ if (request.getAssociationId() == associationId) {
+ requestsByAssociationId.add(request);
+ }
+ }
+ return requestsByAssociationId;
+ }
+
+ void writeRequest(@UserIdInt int userId, SystemDataTransferRequest request) {
+ Slog.i(LOG_TAG, "Writing request=" + request + " to store.");
+ ArrayList<SystemDataTransferRequest> cachedRequests;
+ synchronized (mLock) {
+ // Write to cache
+ cachedRequests = readRequestsFromCache(userId);
+ cachedRequests.add(request);
+ mCachedPerUser.set(userId, cachedRequests);
+ }
+ // Write to store
+ mExecutor.execute(() -> writeRequestsToStore(userId, cachedRequests));
+ }
+
+ /**
+ * Remove requests by association id. userId must be the one which owns the associationId.
+ */
+ public void removeRequestsByAssociationId(@UserIdInt int userId, int associationId) {
+ Slog.i(LOG_TAG, "Removing system data transfer requests for userId=" + userId
+ + ", associationId=" + associationId);
+ ArrayList<SystemDataTransferRequest> cachedRequests;
+ synchronized (mLock) {
+ // Remove requests from cache
+ cachedRequests = readRequestsFromCache(userId);
+ cachedRequests.removeIf(request -> request.getAssociationId() == associationId);
+ mCachedPerUser.set(userId, cachedRequests);
+ }
+ // Remove requests from store
+ mExecutor.execute(() -> writeRequestsToStore(userId, cachedRequests));
+ }
+
+ @GuardedBy("mLock")
+ private ArrayList<SystemDataTransferRequest> readRequestsFromCache(@UserIdInt int userId) {
+ ArrayList<SystemDataTransferRequest> cachedRequests = mCachedPerUser.get(userId);
+ if (cachedRequests == null) {
+ Future<ArrayList<SystemDataTransferRequest>> future =
+ mExecutor.submit(() -> readRequestsFromStore(userId));
+ try {
+ cachedRequests = future.get(READ_FROM_DISK_TIMEOUT, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Slog.e(LOG_TAG, "Thread reading SystemDataTransferRequest from disk is "
+ + "interrupted.");
+ } catch (ExecutionException e) {
+ Slog.e(LOG_TAG, "Error occurred while reading SystemDataTransferRequest "
+ + "from disk.");
+ } catch (TimeoutException e) {
+ Slog.e(LOG_TAG, "Reading SystemDataTransferRequest from disk timed out.");
+ }
+ mCachedPerUser.set(userId, cachedRequests);
+ }
+ return cachedRequests;
+ }
+
/**
* Reads previously persisted data for the given user
*
@@ -92,7 +179,7 @@ public class SystemDataTransferRequestDataStore {
* @return a list of SystemDataTransferRequest
*/
@NonNull
- List<SystemDataTransferRequest> readRequestsForUser(@UserIdInt int userId) {
+ private ArrayList<SystemDataTransferRequest> readRequestsFromStore(@UserIdInt int userId) {
final AtomicFile file = getStorageFileForUser(userId);
Slog.i(LOG_TAG, "Reading SystemDataTransferRequests for user " + userId + " from "
+ "file=" + file.getBaseFile().getPath());
@@ -102,59 +189,62 @@ public class SystemDataTransferRequestDataStore {
synchronized (file) {
if (!file.getBaseFile().exists()) {
Slog.d(LOG_TAG, "File does not exist -> Abort");
- return Collections.emptyList();
+ return new ArrayList<>();
}
try (FileInputStream in = file.openRead()) {
final TypedXmlPullParser parser = Xml.resolvePullParser(in);
XmlUtils.beginDocument(parser, XML_TAG_REQUESTS);
- return readRequests(parser);
+ return readRequestsFromXml(parser);
} catch (XmlPullParserException | IOException e) {
Slog.e(LOG_TAG, "Error while reading requests file", e);
- return Collections.emptyList();
+ return new ArrayList<>();
}
}
}
@NonNull
- private List<SystemDataTransferRequest> readRequests(@NonNull TypedXmlPullParser parser)
- throws XmlPullParserException, IOException {
+ private ArrayList<SystemDataTransferRequest> readRequestsFromXml(
+ @NonNull TypedXmlPullParser parser) throws XmlPullParserException, IOException {
if (!isStartOfTag(parser, XML_TAG_REQUESTS)) {
throw new XmlPullParserException("The XML doesn't have start tag: " + XML_TAG_REQUESTS);
}
- List<SystemDataTransferRequest> requests = new ArrayList<>();
+ ArrayList<SystemDataTransferRequest> requests = new ArrayList<>();
while (true) {
parser.nextTag();
- if (isEndOfTag(parser, XML_TAG_REQUESTS)) break;
+ if (isEndOfTag(parser, XML_TAG_REQUESTS)) {
+ break;
+ }
if (isStartOfTag(parser, XML_TAG_REQUEST)) {
- requests.add(readRequest(parser));
+ requests.add(readRequestFromXml(parser));
}
}
return requests;
}
- private SystemDataTransferRequest readRequest(@NonNull TypedXmlPullParser parser)
+ private SystemDataTransferRequest readRequestFromXml(@NonNull TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
if (!isStartOfTag(parser, XML_TAG_REQUEST)) {
throw new XmlPullParserException("XML doesn't have start tag: " + XML_TAG_REQUEST);
}
final int associationId = readIntAttribute(parser, XML_ATTR_ASSOCIATION_ID);
- final boolean isPermissionSyncAllPackages = readBooleanAttribute(parser,
- XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES);
- parser.nextTag();
- List<String> permissionSyncPackages = new ArrayList<>();
- if (isStartOfTag(parser, XML_TAG_LIST)) {
- parser.nextTag();
- permissionSyncPackages = readThisListXml(parser, XML_TAG_LIST,
- new String[1]);
- }
+ final int dataType = readIntAttribute(parser, XML_ATTR_DATA_TYPE);
+ final int userId = readIntAttribute(parser, XML_ATTR_USER_ID);
+ final boolean isUserConsented = readBooleanAttribute(parser, XML_ATTR_IS_USER_CONSENTED);
- return new SystemDataTransferRequest(associationId, isPermissionSyncAllPackages,
- permissionSyncPackages);
+ switch (dataType) {
+ case DATA_TYPE_PERMISSION_SYNC:
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserId(userId);
+ request.setUserConsented(isUserConsented);
+ return request;
+ default:
+ return null;
+ }
}
/**
@@ -163,7 +253,7 @@ public class SystemDataTransferRequestDataStore {
* @param userId Android UserID
* @param requests a list of user's SystemDataTransferRequest.
*/
- void writeRequestsForUser(@UserIdInt int userId,
+ void writeRequestsToStore(@UserIdInt int userId,
@NonNull List<SystemDataTransferRequest> requests) {
final AtomicFile file = getStorageFileForUser(userId);
Slog.i(LOG_TAG, "Writing SystemDataTransferRequests for user " + userId + " to file="
@@ -177,37 +267,31 @@ public class SystemDataTransferRequestDataStore {
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
- writeRequests(serializer, requests);
+ writeRequestsToXml(serializer, requests);
serializer.endDocument();
});
}
}
- private void writeRequests(@NonNull TypedXmlSerializer serializer,
+ private void writeRequestsToXml(@NonNull TypedXmlSerializer serializer,
@Nullable Collection<SystemDataTransferRequest> requests) throws IOException {
serializer.startTag(null, XML_TAG_REQUESTS);
for (SystemDataTransferRequest request : requests) {
- writeRequest(serializer, request);
+ writeRequestToXml(serializer, request);
}
serializer.endTag(null, XML_TAG_REQUESTS);
}
- private void writeRequest(@NonNull TypedXmlSerializer serializer,
+ private void writeRequestToXml(@NonNull TypedXmlSerializer serializer,
@NonNull SystemDataTransferRequest request) throws IOException {
serializer.startTag(null, XML_TAG_REQUEST);
writeIntAttribute(serializer, XML_ATTR_ASSOCIATION_ID, request.getAssociationId());
- writeBooleanAttribute(serializer, XML_ATTR_IS_PERMISSION_SYNC_ALL_PACKAGES,
- request.isPermissionSyncAllPackages());
- try {
- writeListXml(request.getPermissionSyncPackages(), XML_ATTR_PERMISSION_SYNC_PACKAGES,
- serializer);
- } catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, "Error writing permission sync packages into XML. "
- + request.getPermissionSyncPackages().toString());
- }
+ writeIntAttribute(serializer, XML_ATTR_DATA_TYPE, request.getDataType());
+ writeIntAttribute(serializer, XML_ATTR_USER_ID, request.getUserId());
+ writeBooleanAttribute(serializer, XML_ATTR_IS_USER_CONSENTED, request.isUserConsented());
serializer.endTag(null, XML_TAG_REQUEST);
}
@@ -215,11 +299,12 @@ public class SystemDataTransferRequestDataStore {
/**
* Creates and caches {@link AtomicFile} object that represents the back-up file for the given
* user.
- *
+ * <p>
* IMPORTANT: the method will ALWAYS return the same {@link AtomicFile} object, which makes it
* possible to synchronize reads and writes to the file using the returned object.
*/
- private @NonNull AtomicFile getStorageFileForUser(@UserIdInt int userId) {
+ @NonNull
+ private AtomicFile getStorageFileForUser(@UserIdInt int userId) {
return mUserIdToStorageFile.computeIfAbsent(userId,
u -> createStorageFileForUser(userId, FILE_NAME));
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java
new file mode 100644
index 000000000000..5e3c4c7834fe
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/BackupHelper.java
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup;
+
+import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES;
+
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+import android.permission.PermissionManager.SplitPermissionInfo;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.companion.datatransfer.permbackup.model.AppPermissionGroup;
+import com.android.server.companion.datatransfer.permbackup.model.AppPermissions;
+import com.android.server.companion.datatransfer.permbackup.model.Permission;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for creating and restoring permission backups.
+ */
+public class BackupHelper {
+ private static final String LOG_TAG = BackupHelper.class.getSimpleName();
+
+ private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup";
+ private static final String ATTR_PLATFORM_VERSION = "version";
+
+ private static final String TAG_ALL_GRANTS = "rt-grants";
+
+ private static final String TAG_GRANT = "grant";
+ private static final String ATTR_PACKAGE_NAME = "pkg";
+ private static final String ATTR_HAS_MULTIPLE_SIGNERS = "multi-signers";
+
+ private static final String TAG_SIGNATURE = "sig";
+ private static final String ATTR_SIGNATURE_VALUE = "v";
+
+ private static final String TAG_PERMISSION = "perm";
+ private static final String ATTR_PERMISSION_NAME = "name";
+ private static final String ATTR_IS_GRANTED = "g";
+ private static final String ATTR_USER_SET = "set";
+ private static final String ATTR_USER_FIXED = "fixed";
+ private static final String ATTR_WAS_REVIEWED = "was-reviewed";
+
+ /** Flags of permissions to <u>not</u> back up */
+ private static final int SYSTEM_RUNTIME_GRANT_MASK = FLAG_PERMISSION_POLICY_FIXED
+ | FLAG_PERMISSION_SYSTEM_FIXED;
+
+ /** Make sure only one user can change the delayed permissions at a time */
+ private static final Object sLock = new Object();
+
+ private final Context mContext;
+
+ /**
+ * Create a new backup utils for a user.
+ *
+ * @param context A context to use
+ * @param user The user that is backed up / restored
+ */
+ public BackupHelper(@NonNull Context context, @NonNull UserHandle user) {
+ try {
+ mContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
+ } catch (PackageManager.NameNotFoundException doesNotHappen) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Forward parser and skip everything up to the end of the current tag.
+ *
+ * @param parser The parser to forward
+ */
+ private static void skipToEndOfTag(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int numOpenTags = 1;
+ while (numOpenTags > 0) {
+ switch (parser.next()) {
+ case START_TAG:
+ numOpenTags++;
+ break;
+ case END_TAG:
+ numOpenTags--;
+ break;
+ default:
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Forward parser to a given direct sub-tag.
+ *
+ * @param parser The parser to forward
+ * @param tag The tag to search for
+ */
+ private void skipToTag(@NonNull XmlPullParser parser, @NonNull String tag)
+ throws IOException, XmlPullParserException {
+ int type;
+ do {
+ type = parser.next();
+
+ switch (type) {
+ case START_TAG:
+ if (!parser.getName().equals(tag)) {
+ skipToEndOfTag(parser);
+ }
+
+ return;
+ }
+ } while (type != END_DOCUMENT);
+ }
+
+ /**
+ * Read a XML file and return the packages stored in it.
+ *
+ * @param parser The file to read
+ *
+ * @return The packages in this file
+ */
+ private @NonNull ArrayList<BackupPackageState> parseFromXml(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ ArrayList<BackupPackageState> pkgStates = new ArrayList<>();
+
+ skipToTag(parser, TAG_PERMISSION_BACKUP);
+
+ int backupPlatformVersion;
+ try {
+ backupPlatformVersion = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_PLATFORM_VERSION));
+ } catch (NumberFormatException ignored) {
+ // Platforms P and before did not store the platform version
+ backupPlatformVersion = Build.VERSION_CODES.P;
+ }
+
+ skipToTag(parser, TAG_ALL_GRANTS);
+
+ if (parser.getEventType() != START_TAG && !parser.getName().equals(TAG_ALL_GRANTS)) {
+ throw new XmlPullParserException("Could not find " + TAG_PERMISSION_BACKUP + " > "
+ + TAG_ALL_GRANTS);
+ }
+
+ // Read packages to restore from xml
+ int type;
+ do {
+ type = parser.next();
+
+ switch (type) {
+ case START_TAG:
+ switch (parser.getName()) {
+ case TAG_GRANT:
+ try {
+ pkgStates.add(BackupPackageState.parseFromXml(parser, mContext,
+ backupPlatformVersion));
+ } catch (XmlPullParserException e) {
+ Log.e(LOG_TAG, "Could not parse permissions ", e);
+ skipToEndOfTag(parser);
+ }
+ break;
+ default:
+ // ignore tag
+ Log.w(LOG_TAG, "Found unexpected tag " + parser.getName()
+ + " during restore");
+ skipToEndOfTag(parser);
+ }
+ }
+ } while (type != END_DOCUMENT);
+
+ return pkgStates;
+ }
+
+ /**
+ * Try to restore the permission state from XML.
+ *
+ * @param parser The xml to read
+ */
+ public void restoreState(@NonNull XmlPullParser parser) throws IOException,
+ XmlPullParserException {
+ ArrayList<BackupPackageState> pkgStates = parseFromXml(parser);
+
+ ArrayList<BackupPackageState> packagesToRestoreLater = new ArrayList<>();
+ int numPkgStates = pkgStates.size();
+ if (numPkgStates > 0) {
+ // Try to restore packages
+ for (int i = 0; i < numPkgStates; i++) {
+ BackupPackageState pkgState = pkgStates.get(i);
+
+ PackageInfo pkgInfo;
+ try {
+ pkgInfo = mContext.getPackageManager().getPackageInfo(pkgState.mPackageName,
+ GET_PERMISSIONS | GET_SIGNING_CERTIFICATES);
+ } catch (PackageManager.NameNotFoundException ignored) {
+ packagesToRestoreLater.add(pkgState);
+ continue;
+ }
+
+ pkgState.restore(mContext, pkgInfo);
+ }
+ }
+
+// synchronized (sLock) {
+// writeDelayedStorePkgsLocked(packagesToRestoreLater);
+// }
+ }
+
+ /**
+ * Write a xml file for the given packages.
+ *
+ * @param serializer The file to write to
+ * @param pkgs The packages to write
+ */
+ private static void writePkgsAsXml(@NonNull XmlSerializer serializer,
+ @NonNull ArrayList<BackupPackageState> pkgs) throws IOException {
+ serializer.startDocument(null, true);
+
+ serializer.startTag(null, TAG_PERMISSION_BACKUP);
+
+// if (SDK_INT >= Build.VERSION_CODES.Q) {
+ // STOPSHIP: Remove compatibility code once Q SDK level is declared
+ serializer.attribute(null, ATTR_PLATFORM_VERSION,
+ Integer.valueOf(Build.VERSION_CODES.Q).toString());
+// } else {
+// serializer.attribute(null, ATTR_PLATFORM_VERSION,
+// Integer.valueOf(SDK_INT).toString());
+// }
+
+ serializer.startTag(null, TAG_ALL_GRANTS);
+
+ int numPkgs = pkgs.size();
+ for (int i = 0; i < numPkgs; i++) {
+ BackupPackageState packageState = pkgs.get(i);
+
+ if (packageState != null) {
+ packageState.writeAsXml(serializer);
+ }
+ }
+
+ serializer.endTag(null, TAG_ALL_GRANTS);
+ serializer.endTag(null, TAG_PERMISSION_BACKUP);
+
+ serializer.endDocument();
+ }
+
+ /**
+ * Write the state of all packages as XML.
+ *
+ * @param serializer The xml to write to
+ */
+ public void writeState(@NonNull XmlSerializer serializer) throws IOException {
+ List<PackageInfo> pkgs = mContext.getPackageManager().getInstalledPackages(
+ GET_PERMISSIONS | GET_SIGNING_CERTIFICATES);
+ ArrayList<BackupPackageState> backupPkgs = new ArrayList<>();
+
+ int numPkgs = pkgs.size();
+ for (int i = 0; i < numPkgs; i++) {
+ BackupPackageState packageState = BackupPackageState.fromAppPermissions(mContext,
+ pkgs.get(i));
+
+ if (packageState != null) {
+ backupPkgs.add(packageState);
+ }
+ }
+
+ writePkgsAsXml(serializer, backupPkgs);
+ }
+
+ /**
+ * State that needs to be backed up for a permission.
+ */
+ private static class BackupPermissionState {
+ private final @NonNull String mPermissionName;
+ private final boolean mIsGranted;
+ private final boolean mIsUserSet;
+ private final boolean mIsUserFixed;
+ private final boolean mWasReviewed;
+
+ private BackupPermissionState(@NonNull String permissionName, boolean isGranted,
+ boolean isUserSet, boolean isUserFixed, boolean wasReviewed) {
+ mPermissionName = permissionName;
+ mIsGranted = isGranted;
+ mIsUserSet = isUserSet;
+ mIsUserFixed = isUserFixed;
+ mWasReviewed = wasReviewed;
+ }
+
+ /**
+ * Parse a package state from XML.
+ *
+ * @param parser The data to read
+ * @param context a context to use
+ * @param backupPlatformVersion The platform version the backup was created on
+ *
+ * @return The state
+ */
+ static @NonNull List<BackupPermissionState> parseFromXml(@NonNull XmlPullParser parser,
+ @NonNull Context context, int backupPlatformVersion)
+ throws XmlPullParserException {
+ String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
+ if (permName == null) {
+ throw new XmlPullParserException("Found " + TAG_PERMISSION + " without "
+ + ATTR_PERMISSION_NAME);
+ }
+
+ ArrayList<String> expandedPermissions = new ArrayList<>();
+ expandedPermissions.add(permName);
+
+ List<SplitPermissionInfo> splitPerms = context.getSystemService(
+ PermissionManager.class).getSplitPermissions();
+
+ // Expand the properties to permissions that were split between the platform version the
+ // backup was taken and the current version.
+ int numSplitPerms = splitPerms.size();
+ for (int i = 0; i < numSplitPerms; i++) {
+ SplitPermissionInfo splitPerm = splitPerms.get(i);
+ if (backupPlatformVersion < splitPerm.getTargetSdk()
+ && permName.equals(splitPerm.getSplitPermission())) {
+ expandedPermissions.addAll(splitPerm.getNewPermissions());
+ }
+ }
+
+ ArrayList<BackupPermissionState> parsedPermissions = new ArrayList<>(
+ expandedPermissions.size());
+ int numExpandedPerms = expandedPermissions.size();
+ for (int i = 0; i < numExpandedPerms; i++) {
+ parsedPermissions.add(new BackupPermissionState(expandedPermissions.get(i),
+ "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED)),
+ "true".equals(parser.getAttributeValue(null, ATTR_USER_SET)),
+ "true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED)),
+ "true".equals(parser.getAttributeValue(null, ATTR_WAS_REVIEWED))));
+ }
+
+ return parsedPermissions;
+ }
+
+ /**
+ * Is the permission granted, also considering the app-op.
+ *
+ * <p>This does not consider the review-required state of the permission.
+ *
+ * @param perm The permission that might be granted
+ *
+ * @return {@code true} iff the permission and app-op is granted
+ */
+ private static boolean isPermGrantedIncludingAppOp(@NonNull Permission perm) {
+ return perm.isGranted() && (!perm.affectsAppOp() || perm.isAppOpAllowed());
+ }
+
+ /**
+ * Get the state of a permission to back up.
+ *
+ * @param perm The permission to back up
+ * @param appSupportsRuntimePermissions If the app supports runtimePermissions
+ *
+ * @return The state to back up or {@code null} if the permission does not need to be
+ * backed up.
+ */
+ private static @Nullable BackupPermissionState fromPermission(@NonNull Permission perm,
+ boolean appSupportsRuntimePermissions) {
+ int grantFlags = perm.getFlags();
+
+ if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) != 0) {
+ return null;
+ }
+
+ if (!perm.isUserSet() && perm.isGrantedByDefault()) {
+ return null;
+ }
+
+ boolean permissionWasReviewed;
+ boolean isNotInDefaultGrantState;
+ if (appSupportsRuntimePermissions) {
+ isNotInDefaultGrantState = isPermGrantedIncludingAppOp(perm);
+ permissionWasReviewed = false;
+ } else {
+ isNotInDefaultGrantState = !isPermGrantedIncludingAppOp(perm);
+ permissionWasReviewed = !perm.isReviewRequired();
+ }
+
+// if (isNotInDefaultGrantState || perm.isUserSet() || perm.isUserFixed()
+// || permissionWasReviewed) {
+// return new BackupPermissionState(perm.getName(),
+// isPermGrantedIncludingAppOp(perm),
+// perm.isUserSet(), perm.isUserFixed(), permissionWasReviewed);
+// } else {
+// return null;
+// }
+ if (perm.isUserSet() && isPermGrantedIncludingAppOp(perm)) {
+ return new BackupPermissionState(perm.getName(), /* isGranted */ true,
+ /* isUserSet */ true, perm.isUserFixed(), permissionWasReviewed);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the states of all permissions of a group to back up.
+ *
+ * @param group The group of the permissions to back up
+ *
+ * @return The state to back up. Empty list if no permissions in the group need to be backed
+ * up
+ */
+ static @NonNull ArrayList<BackupPermissionState> fromPermissionGroup(
+ @NonNull AppPermissionGroup group) {
+ ArrayList<BackupPermissionState> permissionsToRestore = new ArrayList<>();
+ List<Permission> perms = group.getPermissions();
+
+ boolean appSupportsRuntimePermissions =
+ group.getApp().applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+
+ int numPerms = perms.size();
+ for (int i = 0; i < numPerms; i++) {
+ BackupPermissionState permState = fromPermission(perms.get(i),
+ appSupportsRuntimePermissions);
+ if (permState != null) {
+ permissionsToRestore.add(permState);
+ }
+ }
+
+ return permissionsToRestore;
+ }
+
+ /**
+ * Write this state as XML.
+ *
+ * @param serializer The file to write to
+ */
+ void writeAsXml(@NonNull XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, TAG_PERMISSION);
+
+ serializer.attribute(null, ATTR_PERMISSION_NAME, mPermissionName);
+
+ if (mIsGranted) {
+ serializer.attribute(null, ATTR_IS_GRANTED, "true");
+ }
+
+ if (mIsUserSet) {
+ serializer.attribute(null, ATTR_USER_SET, "true");
+ }
+
+ if (mIsUserFixed) {
+ serializer.attribute(null, ATTR_USER_FIXED, "true");
+ }
+
+ if (mWasReviewed) {
+ serializer.attribute(null, ATTR_WAS_REVIEWED, "true");
+ }
+
+ serializer.endTag(null, TAG_PERMISSION);
+ }
+
+ /**
+ * Restore this permission state.
+ *
+ * @param appPerms The {@link AppPermissions} to restore the state to
+ * @param restoreBackgroundPerms if {@code true} only restore background permissions,
+ * if {@code false} do not restore background permissions
+ */
+ void restore(@NonNull AppPermissions appPerms, boolean restoreBackgroundPerms) {
+ AppPermissionGroup group = appPerms.getGroupForPermission(mPermissionName);
+ if (group == null) {
+ Log.w(LOG_TAG, "Could not find group for " + mPermissionName + " in "
+ + appPerms.getPackageInfo().packageName);
+ return;
+ }
+
+ if (restoreBackgroundPerms != group.isBackgroundGroup()) {
+ return;
+ }
+
+ Permission perm = group.getPermission(mPermissionName);
+ if (mWasReviewed) {
+ perm.unsetReviewRequired();
+ }
+
+ // Don't grant or revoke fixed permission groups
+ if (group.isSystemFixed() || group.isPolicyFixed()) {
+ return;
+ }
+
+ if (!perm.isUserSet()) {
+ if (mIsGranted) {
+ group.grantRuntimePermissions(false, mIsUserFixed,
+ new String[]{mPermissionName});
+ } else {
+ group.revokeRuntimePermissions(mIsUserFixed,
+ new String[]{mPermissionName});
+ }
+
+ perm.setUserSet(mIsUserSet);
+ }
+ }
+ }
+
+ /**
+ * State that needs to be backed up for a package.
+ */
+ private static class BackupPackageState {
+ final @NonNull String mPackageName;
+ final boolean mHasMultipleSigners;
+ @NonNull Signature[] mSignatures;
+ private final @NonNull ArrayList<BackupPermissionState> mPermissionsToRestore;
+
+ private BackupPackageState(@NonNull String packageName, boolean hasMultipleSigners,
+ @NonNull Signature[] signatures,
+ @NonNull ArrayList<BackupPermissionState> permissionsToRestore) {
+ mPackageName = packageName;
+ mHasMultipleSigners = hasMultipleSigners;
+ mSignatures = signatures;
+ mPermissionsToRestore = permissionsToRestore;
+ }
+
+ /**
+ * Parse a package state from XML.
+ *
+ * @param parser The data to read
+ * @param context a context to use
+ * @param backupPlatformVersion The platform version the backup was created on
+ *
+ * @return The state
+ */
+ static @NonNull BackupPackageState parseFromXml(@NonNull XmlPullParser parser,
+ @NonNull Context context, int backupPlatformVersion)
+ throws IOException, XmlPullParserException {
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ if (packageName == null) {
+ throw new XmlPullParserException("Found " + TAG_GRANT + " without "
+ + ATTR_PACKAGE_NAME);
+ }
+
+ boolean hasMultipleSigners = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_HAS_MULTIPLE_SIGNERS));
+ ArrayList<Signature> signatureList = new ArrayList<>();
+
+ ArrayList<BackupPermissionState> permissionsToRestore = new ArrayList<>();
+
+ while (true) {
+ switch (parser.next()) {
+ case START_TAG:
+ switch (parser.getName()) {
+ case TAG_PERMISSION:
+ try {
+ permissionsToRestore.addAll(
+ BackupPermissionState.parseFromXml(parser, context,
+ backupPlatformVersion));
+ } catch (XmlPullParserException e) {
+ Log.e(LOG_TAG, "Could not parse permission for "
+ + packageName, e);
+ }
+
+ skipToEndOfTag(parser);
+ break;
+ case TAG_SIGNATURE:
+ signatureList.add(new Signature(
+ parser.getAttributeValue(null, ATTR_SIGNATURE_VALUE)));
+ skipToEndOfTag(parser);
+ break;
+ default:
+ // ignore tag
+ Log.w(LOG_TAG, "Found unexpected tag " + parser.getName()
+ + " while restoring " + packageName);
+ skipToEndOfTag(parser);
+ }
+
+ break;
+ case END_TAG:
+ Signature[] signatures = new Signature[signatureList.size()];
+ for (int i = 0; i < signatureList.size(); i++) {
+ signatures[i] = signatureList.get(i);
+ }
+ return new BackupPackageState(packageName, hasMultipleSigners, signatures,
+ permissionsToRestore);
+ case END_DOCUMENT:
+ throw new XmlPullParserException("Could not parse state for "
+ + packageName);
+ }
+ }
+ }
+
+ /**
+ * Get the state of a package to back up.
+ *
+ * @param context A context to use
+ * @param pkgInfo The package to back up.
+ *
+ * @return The state to back up or {@code null} if no permission of the package need to be
+ * backed up.
+ */
+ static @Nullable BackupPackageState fromAppPermissions(@NonNull Context context,
+ @NonNull PackageInfo pkgInfo) {
+ AppPermissions appPerms = new AppPermissions(context, pkgInfo, false, null);
+
+ ArrayList<BackupPermissionState> permissionsToRestore = new ArrayList<>();
+ List<AppPermissionGroup> groups = appPerms.getPermissionGroups();
+
+ // Check if the package has signatures
+ SigningInfo signingInfo = pkgInfo.signingInfo;
+ Signature[] signatures;
+ boolean hasMultipleSigners;
+ if (signingInfo.hasMultipleSigners()) {
+ hasMultipleSigners = true;
+ signatures = signingInfo.getApkContentsSigners();
+ } else {
+ hasMultipleSigners = false;
+ signatures = signingInfo.getSigningCertificateHistory();
+ }
+ if (signatures == null) {
+ Slog.d(LOG_TAG, "Skipping " + pkgInfo.packageName + ", it's unsigned.");
+ return null;
+ }
+
+ int numGroups = groups.size();
+ for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+ AppPermissionGroup group = groups.get(groupNum);
+
+ permissionsToRestore.addAll(BackupPermissionState.fromPermissionGroup(group));
+
+ // Background permissions are in a subgroup that is not part of
+ // {@link AppPermission#getPermissionGroups}. Hence add it explicitly here.
+ if (group.getBackgroundPermissions() != null) {
+ permissionsToRestore.addAll(BackupPermissionState.fromPermissionGroup(
+ group.getBackgroundPermissions()));
+ }
+ }
+
+ if (permissionsToRestore.size() == 0) {
+ return null;
+ }
+
+ return new BackupPackageState(pkgInfo.packageName, hasMultipleSigners, signatures,
+ permissionsToRestore);
+ }
+
+ /**
+ * Write this state as XML.
+ *
+ * @param serializer The file to write to
+ */
+ void writeAsXml(@NonNull XmlSerializer serializer) throws IOException {
+ if (mPermissionsToRestore.size() == 0) {
+ return;
+ }
+
+ serializer.startTag(null, TAG_GRANT);
+ serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
+
+ // Add signing info
+ serializer.attribute(null, ATTR_HAS_MULTIPLE_SIGNERS,
+ String.valueOf(mHasMultipleSigners));
+ for (Signature signature : mSignatures) {
+ serializer.startTag(null, TAG_SIGNATURE);
+ serializer.attribute(null, ATTR_SIGNATURE_VALUE, signature.toCharsString());
+ serializer.endTag(null, TAG_SIGNATURE);
+ }
+
+ int numPerms = mPermissionsToRestore.size();
+ for (int i = 0; i < numPerms; i++) {
+ mPermissionsToRestore.get(i).writeAsXml(serializer);
+ }
+
+ serializer.endTag(null, TAG_GRANT);
+ }
+
+ /**
+ * Restore this package state.
+ *
+ * @param context A context to use
+ * @param pkgInfo The package to restore.
+ */
+ void restore(@NonNull Context context, @NonNull PackageInfo pkgInfo) {
+ Slog.e(LOG_TAG, "Restoring permissions for package [" + mPackageName + "]");
+
+ // Verify signature info
+ try {
+ if (mHasMultipleSigners && pkgInfo.signingInfo.hasMultipleSigners()) {
+ // If both packages are signed by multi signers, check if two signature sets are
+ // effectively matched.
+ if (!Signature.areEffectiveMatch(mSignatures,
+ pkgInfo.signingInfo.getApkContentsSigners())) {
+ Slog.e(LOG_TAG, "Multi-signers signatures don't match for package ["
+ + mPackageName + "], skipped.");
+ return;
+ }
+ } else if (!mHasMultipleSigners && !pkgInfo.signingInfo.hasMultipleSigners()) {
+ // If both packages are not signed by multi signers, check if two signature sets
+ // have overlaps.
+ Signature[] signatures = pkgInfo.signingInfo.getSigningCertificateHistory();
+ if (signatures == null) {
+ Slog.e(LOG_TAG, "The dest package is unsigned.");
+ return;
+ }
+ boolean isMatched = false;
+ for (int i = 0; i < mSignatures.length; i++) {
+ for (int j = 0; j < signatures.length; j++) {
+ isMatched = Signature.areEffectiveMatch(mSignatures[i], signatures[j]);
+ }
+ }
+ if (!isMatched) {
+ Slog.e(LOG_TAG, "Single signer signatures don't match for package ["
+ + mPackageName + "], skipped.");
+ return;
+ }
+ } else {
+ Slog.e(LOG_TAG, "Number of signers don't match.");
+ return;
+ }
+ } catch (CertificateException ce) {
+ Slog.e(LOG_TAG, "Either the source or the dest package's bounced cert length "
+ + "looks fishy, skipped package [" + pkgInfo.packageName + "]");
+ }
+
+ AppPermissions appPerms = new AppPermissions(context, pkgInfo, false, true, null);
+
+ ArraySet<String> affectedPermissions = new ArraySet<>();
+ // Restore background permissions after foreground permissions as for pre-M apps bg
+ // granted and fg revoked cannot be expressed.
+ int numPerms = mPermissionsToRestore.size();
+ for (int i = 0; i < numPerms; i++) {
+ mPermissionsToRestore.get(i).restore(appPerms, false);
+ affectedPermissions.add(mPermissionsToRestore.get(i).mPermissionName);
+ }
+ for (int i = 0; i < numPerms; i++) {
+ mPermissionsToRestore.get(i).restore(appPerms, true);
+ }
+
+ int numGroups = appPerms.getPermissionGroups().size();
+ for (int i = 0; i < numGroups; i++) {
+ AppPermissionGroup group = appPerms.getPermissionGroups().get(i);
+
+ // Only denied groups can be user fixed
+ if (group.areRuntimePermissionsGranted()) {
+ group.setUserFixed(false);
+ }
+
+ AppPermissionGroup bgGroup = group.getBackgroundPermissions();
+ if (bgGroup != null) {
+ // Only denied groups can be user fixed
+ if (bgGroup.areRuntimePermissionsGranted()) {
+ bgGroup.setUserFixed(false);
+ }
+ }
+ }
+
+ appPerms.persistChanges(true, affectedPermissions);
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java
new file mode 100644
index 000000000000..cf146ac7a48e
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissionGroup.java
@@ -0,0 +1,1574 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.model;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.server.companion.datatransfer.permbackup.utils.ArrayUtils;
+import com.android.server.companion.datatransfer.permbackup.utils.LocationUtils;
+import com.android.server.companion.datatransfer.permbackup.utils.SoftRestrictedPermissionPolicy;
+import com.android.server.companion.datatransfer.permbackup.utils.Utils;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * All permissions of a permission group that are requested by an app.
+ *
+ * <p>Some permissions only grant access to the protected resource while the app is running in the
+ * foreground. These permissions are considered "split" into this foreground and a matching
+ * "background" permission.
+ *
+ * <p>All background permissions of the group are not in the main group and will not be affected
+ * by operations on the group. The background permissions can be found in the {@link
+ * #getBackgroundPermissions() background permissions group}.
+ */
+public final class AppPermissionGroup implements Comparable<AppPermissionGroup> {
+ private static final String LOG_TAG = AppPermissionGroup.class.getSimpleName();
+ private static final String PLATFORM_PACKAGE_NAME = "android";
+
+ private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
+
+ /**
+ * Importance level to define the threshold for whether a package is in a state which resets the
+ * timer on its one-time permission session
+ */
+ private static final int ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER =
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+
+ /**
+ * Importance level to define the threshold for whether a package is in a state which keeps its
+ * one-time permission session alive after the timer ends
+ */
+ private static final int ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE =
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
+ private final Context mContext;
+ private final UserHandle mUserHandle;
+ private final PackageManager mPackageManager;
+ private final AppOpsManager mAppOps;
+ private final ActivityManager mActivityManager;
+ private final Collator mCollator;
+
+ private final PackageInfo mPackageInfo;
+ private final String mName;
+ private final String mDeclaringPackage;
+ private final CharSequence mLabel;
+ private final CharSequence mFullLabel;
+ private final @StringRes int mRequest;
+ private final @StringRes int mRequestDetail;
+ private final @StringRes int mBackgroundRequest;
+ private final @StringRes int mBackgroundRequestDetail;
+ private final @StringRes int mUpgradeRequest;
+ private final @StringRes int mUpgradeRequestDetail;
+ private final CharSequence mDescription;
+ private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
+ private final String mIconPkg;
+ private final int mIconResId;
+
+ /** Delay changes until {@link #persistChanges} is called */
+ private final boolean mDelayChanges;
+
+ /**
+ * Some permissions are split into foreground and background permission. All non-split and
+ * foreground permissions are in {@link #mPermissions}, all background permissions are in
+ * this field.
+ */
+ private AppPermissionGroup mBackgroundPermissions;
+
+ private final boolean mAppSupportsRuntimePermissions;
+ private final boolean mIsEphemeralApp;
+ private final boolean mIsNonIsolatedStorage;
+ private boolean mContainsEphemeralPermission;
+ private boolean mContainsPreRuntimePermission;
+
+ /**
+ * Does this group contain at least one permission that is split into a foreground and
+ * background permission? This does not necessarily mean that the app also requested the
+ * background permission.
+ */
+ private boolean mHasPermissionWithBackgroundMode;
+
+ private boolean mTriggerLocationAccessCheckOnPersist;
+
+ private boolean mIsSelfRevoked;
+
+ /**
+ * Create the app permission group.
+ *
+ * @param context the {@code Context} to retrieve system services.
+ * @param packageInfo package information about the app.
+ * @param permissionName the name of the permission this object represents.
+ * @param delayChanges whether to delay changes until {@link #persistChanges} is called.
+ *
+ * @return the AppPermissionGroup.
+ */
+ public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
+ String permissionName, boolean delayChanges) {
+ PermissionInfo permissionInfo;
+ try {
+ permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+
+ if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ != PermissionInfo.PROTECTION_DANGEROUS
+ || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+ return null;
+ }
+
+ String group = Utils.getGroupOfPermission(permissionInfo);
+ PackageItemInfo groupInfo = permissionInfo;
+ if (group != null) {
+ try {
+ groupInfo = context.getPackageManager().getPermissionGroupInfo(group, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+
+ List<PermissionInfo> permissionInfos = null;
+ if (groupInfo instanceof PermissionGroupInfo) {
+ try {
+ permissionInfos = Utils.getPermissionInfosForGroup(context.getPackageManager(),
+ groupInfo.name);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+
+ return create(context, packageInfo, groupInfo, permissionInfos, delayChanges);
+ }
+
+ /**
+ * Create the app permission group.
+ *
+ * @param app the current application
+ * @param packageName the name of the package
+ * @param permissionGroupName the name of the permission group
+ * @param user the user of the package
+ * @param delayChanges whether to delay changes until {@link #persistChanges} is called.
+ *
+ * @return the AppPermissionGroup.
+ */
+ public static AppPermissionGroup create(Application app, String packageName,
+ String permissionGroupName, UserHandle user, boolean delayChanges) {
+ try {
+ PackageInfo packageInfo = Utils.getUserContext(app, user).getPackageManager()
+ .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+ PackageItemInfo groupInfo = Utils.getGroupInfo(permissionGroupName, app);
+ if (groupInfo == null) {
+ return null;
+ }
+
+ List<PermissionInfo> permissionInfos = null;
+ if (groupInfo instanceof PermissionGroupInfo) {
+ permissionInfos = Utils.getPermissionInfosForGroup(app.getPackageManager(),
+ groupInfo.name);
+ }
+ return create(app, packageInfo, groupInfo, permissionInfos, delayChanges);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Create the app permission group.
+ *
+ * @param context the {@code Context} to retrieve system services.
+ * @param packageInfo package information about the app.
+ * @param groupInfo the information about the group created.
+ * @param permissionInfos the information about the permissions belonging to the group.
+ * @param delayChanges whether to delay changes until {@link #persistChanges} is called.
+ *
+ * @return the AppPermissionGroup.
+ */
+ public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
+ PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos, boolean delayChanges) {
+ PackageManager packageManager = context.getPackageManager();
+ CharSequence groupLabel = groupInfo.loadLabel(packageManager);
+ CharSequence fullGroupLabel = groupInfo.loadSafeLabel(packageManager, 0,
+ TextUtils.SAFE_STRING_FLAG_TRIM | TextUtils.SAFE_STRING_FLAG_FIRST_LINE);
+ return create(context, packageInfo, groupInfo, permissionInfos, groupLabel,
+ fullGroupLabel, delayChanges);
+ }
+
+ /**
+ * Create the app permission group.
+ *
+ * @param context the {@code Context} to retrieve system services.
+ * @param packageInfo package information about the app.
+ * @param groupInfo the information about the group created.
+ * @param permissionInfos the information about the permissions belonging to the group.
+ * @param groupLabel the label of the group.
+ * @param fullGroupLabel the untruncated label of the group.
+ * @param delayChanges whether to delay changes until {@link #persistChanges} is called.
+ *
+ * @return the AppPermissionGroup.
+ */
+ public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
+ PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos,
+ CharSequence groupLabel, CharSequence fullGroupLabel, boolean delayChanges) {
+ PackageManager packageManager = context.getPackageManager();
+ UserHandle userHandle = UserHandle.getUserHandleForUid(packageInfo.applicationInfo.uid);
+
+ if (groupInfo instanceof PermissionInfo) {
+ permissionInfos = new ArrayList<>();
+ permissionInfos.add((PermissionInfo) groupInfo);
+ }
+
+ if (permissionInfos == null || permissionInfos.isEmpty()) {
+ return null;
+ }
+
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
+ AppPermissionGroup group = new AppPermissionGroup(context, packageInfo, groupInfo.name,
+ groupInfo.packageName, groupLabel, fullGroupLabel,
+ /* description */ null, /* request */ 0,
+ /* requestDetail */ 0, /* backgroundRequest */ 0,
+ /* backgroundRequestDetail */ 0, /* upgradeRequest */0,
+ /* upgradeRequestDetail */ 0, groupInfo.packageName, groupInfo.icon,
+ userHandle, delayChanges, appOpsManager);
+
+ final Set<String> exemptedRestrictedPermissions = context.getPackageManager()
+ .getWhitelistedRestrictedPermissions(packageInfo.packageName,
+ Utils.FLAGS_PERMISSION_WHITELIST_ALL);
+
+ // Parse and create permissions requested by the app
+ ArrayMap<String, Permission> allPermissions = new ArrayMap<>();
+ final int permissionCount = packageInfo.requestedPermissions == null ? 0
+ : packageInfo.requestedPermissions.length;
+ String packageName = packageInfo.packageName;
+ for (int i = 0; i < permissionCount; i++) {
+ String requestedPermission = packageInfo.requestedPermissions[i];
+
+ PermissionInfo requestedPermissionInfo = null;
+
+ for (PermissionInfo permissionInfo : permissionInfos) {
+ if (requestedPermission.equals(permissionInfo.name)) {
+ requestedPermissionInfo = permissionInfo;
+ break;
+ }
+ }
+
+ if (requestedPermissionInfo == null) {
+ continue;
+ }
+
+ // Collect only runtime permissions.
+ if ((requestedPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ != PermissionInfo.PROTECTION_DANGEROUS) {
+ continue;
+ }
+
+ // Don't allow toggling non-platform permission groups for legacy apps via app ops.
+ if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
+ && !PLATFORM_PACKAGE_NAME.equals(groupInfo.packageName)) {
+ continue;
+ }
+
+ final boolean granted = (packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+
+ final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
+ ? AppOpsManager.permissionToOp(requestedPermissionInfo.name) : null;
+
+ final boolean appOpAllowed;
+ if (appOp == null) {
+ appOpAllowed = false;
+ } else {
+ int appOpsMode = appOpsManager.unsafeCheckOpRaw(appOp,
+ packageInfo.applicationInfo.uid, packageName);
+ appOpAllowed = appOpsMode == MODE_ALLOWED || appOpsMode == MODE_FOREGROUND;
+ }
+
+ final int flags = packageManager.getPermissionFlags(
+ requestedPermission, packageName, userHandle);
+
+ Permission permission = new Permission(requestedPermission, requestedPermissionInfo,
+ granted, appOp, appOpAllowed, flags);
+
+ if (requestedPermissionInfo.backgroundPermission != null) {
+ group.mHasPermissionWithBackgroundMode = true;
+ }
+
+ allPermissions.put(requestedPermission, permission);
+ }
+
+ int numPermissions = allPermissions.size();
+ if (numPermissions == 0) {
+ return null;
+ }
+
+ // Link up foreground and background permissions
+ for (int i = 0; i < allPermissions.size(); i++) {
+ Permission permission = allPermissions.valueAt(i);
+
+ if (permission.getBackgroundPermissionName() != null) {
+ Permission backgroundPermission = allPermissions.get(
+ permission.getBackgroundPermissionName());
+
+ if (backgroundPermission != null) {
+ backgroundPermission.addForegroundPermissions(permission);
+ permission.setBackgroundPermission(backgroundPermission);
+
+ // The background permissions isAppOpAllowed refers to the background state of
+ // the foregound permission's appOp. Hence we can only set it once we know the
+ // matching foreground permission.
+ // @see #allowAppOp
+ if (context.getSystemService(AppOpsManager.class).unsafeCheckOpRaw(
+ permission.getAppOp(), packageInfo.applicationInfo.uid,
+ packageInfo.packageName) == MODE_ALLOWED) {
+ backgroundPermission.setAppOpAllowed(true);
+ }
+ }
+ }
+ }
+
+ // Add permissions found to this group
+ for (int i = 0; i < numPermissions; i++) {
+ Permission permission = allPermissions.valueAt(i);
+
+ if ((!permission.isHardRestricted()
+ || exemptedRestrictedPermissions.contains(permission.getName()))
+ && (!permission.isSoftRestricted()
+ || SoftRestrictedPermissionPolicy.shouldShow(packageInfo, permission))) {
+ if (permission.isBackgroundPermission()) {
+ if (group.getBackgroundPermissions() == null) {
+ group.mBackgroundPermissions = new AppPermissionGroup(group.mContext,
+ group.getApp(), group.getName(), group.getDeclaringPackage(),
+ group.getLabel(), group.getFullLabel(), group.getDescription(),
+ group.getRequest(), group.getRequestDetail(),
+ group.getBackgroundRequest(), group.getBackgroundRequestDetail(),
+ group.getUpgradeRequest(), group.getUpgradeRequestDetail(),
+ group.getIconPkg(), group.getIconResId(), group.getUser(),
+ delayChanges, appOpsManager);
+ }
+
+ group.getBackgroundPermissions().addPermission(permission);
+ } else {
+ group.addPermission(permission);
+ }
+ }
+ }
+
+ if (group.getPermissions().isEmpty()) {
+ return null;
+ }
+
+ return group;
+ }
+
+ private AppPermissionGroup(Context context, PackageInfo packageInfo, String name,
+ String declaringPackage, CharSequence label, CharSequence fullLabel,
+ CharSequence description, @StringRes int request, @StringRes int requestDetail,
+ @StringRes int backgroundRequest, @StringRes int backgroundRequestDetail,
+ @StringRes int upgradeRequest, @StringRes int upgradeRequestDetail,
+ String iconPkg, int iconResId, UserHandle userHandle, boolean delayChanges,
+ @NonNull AppOpsManager appOpsManager) {
+ int targetSDK = packageInfo.applicationInfo.targetSdkVersion;
+
+ mContext = context;
+ mUserHandle = userHandle;
+ mPackageManager = mContext.getPackageManager();
+ mPackageInfo = packageInfo;
+ mAppSupportsRuntimePermissions = targetSDK > Build.VERSION_CODES.LOLLIPOP_MR1;
+ mIsEphemeralApp = packageInfo.applicationInfo.isInstantApp();
+ mAppOps = appOpsManager;
+ mActivityManager = context.getSystemService(ActivityManager.class);
+ mDeclaringPackage = declaringPackage;
+ mName = name;
+ mLabel = label;
+ mFullLabel = fullLabel;
+ mDescription = description;
+ mCollator = Collator.getInstance(
+ context.getResources().getConfiguration().getLocales().get(0));
+ mRequest = request;
+ mRequestDetail = requestDetail;
+ mBackgroundRequest = backgroundRequest;
+ mBackgroundRequestDetail = backgroundRequestDetail;
+ mUpgradeRequest = upgradeRequest;
+ mUpgradeRequestDetail = upgradeRequestDetail;
+ mDelayChanges = delayChanges;
+ if (iconResId != 0) {
+ mIconPkg = iconPkg;
+ mIconResId = iconResId;
+ } else {
+ mIconPkg = context.getPackageName();
+ mIconResId = 0; // doesn't matter to CDM
+ }
+
+ mIsNonIsolatedStorage = targetSDK < Build.VERSION_CODES.P
+ || (targetSDK < Build.VERSION_CODES.R
+ && mAppOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE,
+ packageInfo.applicationInfo.uid, packageInfo.packageName) == MODE_ALLOWED);
+ }
+
+ boolean doesSupportRuntimePermissions() {
+ return mAppSupportsRuntimePermissions;
+ }
+
+ boolean isGrantingAllowed() {
+ return (!mIsEphemeralApp || mContainsEphemeralPermission)
+ && (mAppSupportsRuntimePermissions || mContainsPreRuntimePermission);
+ }
+
+ boolean isReviewRequired() {
+ if (mAppSupportsRuntimePermissions) {
+ return false;
+ }
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isReviewRequired()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Are any of the permissions in this group user sensitive.
+ *
+ * @return {@code true} if any of the permissions in the group is user sensitive.
+ */
+ public boolean isUserSensitive() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isUserSensitive()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void unsetReviewRequired() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isReviewRequired()) {
+ permission.unsetReviewRequired();
+ }
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+ }
+ }
+
+ boolean hasGrantedByDefaultPermission() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isGrantedByDefault()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public PackageInfo getApp() {
+ return mPackageInfo;
+ }
+
+ String getName() {
+ return mName;
+ }
+
+ String getDeclaringPackage() {
+ return mDeclaringPackage;
+ }
+
+ String getIconPkg() {
+ return mIconPkg;
+ }
+
+ int getIconResId() {
+ return mIconResId;
+ }
+
+ CharSequence getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Get the full un-ellipsized label of the permission group.
+ *
+ * @return the full label of the group.
+ */
+ public CharSequence getFullLabel() {
+ return mFullLabel;
+ }
+
+ /**
+ * @hide
+ * @return The resource Id of the request string.
+ */
+ public @StringRes int getRequest() {
+ return mRequest;
+ }
+
+ /**
+ * Get the (subtitle) message explaining to the user that the permission is only granted to
+ * the apps running in the foreground.
+ *
+ * @return the message or 0 if unset
+ */
+ public @StringRes int getRequestDetail() {
+ return mRequestDetail;
+ }
+
+ /**
+ * Get the title of the dialog explaining to the user that the permission is granted while
+ * the app is in background and in foreground.
+ *
+ * @return the message or 0 if unset
+ */
+ public @StringRes int getBackgroundRequest() {
+ return mBackgroundRequest;
+ }
+
+ /**
+ * Get the (subtitle) message explaining to the user that the she/he is about to allow the
+ * app to have background access.
+ *
+ * @return the message or 0 if unset
+ */
+ public @StringRes int getBackgroundRequestDetail() {
+ return mBackgroundRequestDetail;
+ }
+
+ /**
+ * Get the title of the dialog explaining to the user that the permission, which was
+ * previously only granted for foreground, is granted while the app is in background and in
+ * foreground.
+ *
+ * @return the message or 0 if unset
+ */
+ public @StringRes int getUpgradeRequest() {
+ return mUpgradeRequest;
+ }
+
+ /**
+ * Get the (subtitle) message explaining to the user that the she/he is about to allow the
+ * app to have background access while currently having foreground only.
+ *
+ * @return the message or 0 if unset
+ */
+ public @StringRes int getUpgradeRequestDetail() {
+ return mUpgradeRequestDetail;
+ }
+
+ public CharSequence getDescription() {
+ return mDescription;
+ }
+
+ public UserHandle getUser() {
+ return mUserHandle;
+ }
+
+ /**
+ * Check if the group contains the permission.
+ */
+ public boolean hasPermission(String permission) {
+ return mPermissions.get(permission) != null;
+ }
+
+ /**
+ * Return a permission if in this group.
+ *
+ * @param permissionName The name of the permission
+ *
+ * @return The permission
+ */
+ public @Nullable Permission getPermission(@NonNull String permissionName) {
+ return mPermissions.get(permissionName);
+ }
+
+ /**
+ * Check if at least one of the permissions in the entire permission group should be considered
+ * granted.
+ */
+ public boolean areRuntimePermissionsGranted() {
+ return areRuntimePermissionsGranted(null);
+ }
+
+ /**
+ * Check if at least one of the permissions in the filterPermissions should be considered
+ * granted.
+ */
+ public boolean areRuntimePermissionsGranted(String[] filterPermissions) {
+ return areRuntimePermissionsGranted(filterPermissions, false);
+ }
+
+ /**
+ * @param filterPermissions the permissions to check for, null for all in this group
+ * @param asOneTime add the requirement that at least one of the granted permissions must have
+ * the ONE_TIME flag to return true
+ */
+ public boolean areRuntimePermissionsGranted(String[] filterPermissions, boolean asOneTime) {
+ return areRuntimePermissionsGranted(filterPermissions, asOneTime, true);
+ }
+
+ /**
+ * Returns true if at least one of the permissions in filterPermissions (or the entire
+ * permission group if null) should be considered granted and satisfy the requirements
+ * described by asOneTime and includingAppOp.
+ *
+ * @param filterPermissions the permissions to check for, null for all in this group
+ * @param asOneTime add the requirement that the granted permission must have the ONE_TIME flag
+ * @param includingAppOp add the requirement that if the granted permissions has a
+ * corresponding AppOp, it must be allowed.
+ */
+ public boolean areRuntimePermissionsGranted(String[] filterPermissions, boolean asOneTime,
+ boolean includingAppOp) {
+ if (LocationUtils.isLocationGroupAndProvider(mContext, mName, mPackageInfo.packageName)) {
+ return LocationUtils.isLocationEnabled(mContext) && !asOneTime;
+ }
+ // The permission of the extra location controller package is determined by the status of
+ // the controller package itself.
+ if (LocationUtils.isLocationGroupAndControllerExtraPackage(
+ mContext, mName, mPackageInfo.packageName)) {
+ return LocationUtils.isExtraLocationControllerPackageEnabled(mContext) && !asOneTime;
+ }
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (filterPermissions != null
+ && !ArrayUtils.contains(filterPermissions, permission.getName())) {
+ continue;
+ }
+ boolean isGranted = includingAppOp ? permission.isGrantedIncludingAppOp()
+ : permission.isGranted();
+ if (isGranted && (!asOneTime || permission.isOneTime())) {
+ return true;
+ }
+ }
+ if (mBackgroundPermissions != null) {
+ // If asOneTime is true and none of the foreground permissions are one-time, but some
+ // background permissions are, then we still want to return true.
+ return mBackgroundPermissions.areRuntimePermissionsGranted(filterPermissions,
+ asOneTime, includingAppOp);
+ }
+ return false;
+ }
+
+ boolean grantRuntimePermissions(boolean setByTheUser, boolean fixedByTheUser) {
+ return grantRuntimePermissions(setByTheUser, fixedByTheUser, null);
+ }
+
+ /**
+ * Set mode of an app-op if needed.
+ *
+ * @param op The op to set
+ * @param uid The uid the app-op belongs to
+ * @param mode The new mode
+ *
+ * @return {@code true} iff app-op was changed
+ */
+ private boolean setAppOpMode(@NonNull String op, int uid, int mode) {
+ int currentMode = mAppOps.unsafeCheckOpRaw(op, uid, mPackageInfo.packageName);
+ if (currentMode == mode) {
+ return false;
+ }
+
+ mAppOps.setUidMode(op, uid, mode);
+ return true;
+ }
+
+ /**
+ * Allow the app op for a permission/uid.
+ *
+ * <p>There are three cases:
+ * <dl>
+ * <dt>The permission is not split into foreground/background</dt>
+ * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd>
+ * <dt>The permission is a foreground permission:</dt>
+ * <dd><dl><dt>The background permission permission is granted</dt>
+ * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd>
+ * <dt>The background permission permission is <u>not</u> granted</dt>
+ * <dd>The app op matching the permission will be set to
+ * {@link AppOpsManager#MODE_FOREGROUND}</dd>
+ * </dl></dd>
+ * <dt>The permission is a background permission:</dt>
+ * <dd>All granted foreground permissions for this background permission will be set to
+ * {@link AppOpsManager#MODE_ALLOWED}</dd>
+ * </dl>
+ *
+ * @param permission The permission which has an appOps that should be allowed
+ * @param uid The uid of the process the app op is for
+ *
+ * @return {@code true} iff app-op was changed
+ */
+ private boolean allowAppOp(Permission permission, int uid) {
+ boolean wasChanged = false;
+
+ if (permission.isBackgroundPermission()) {
+ ArrayList<Permission> foregroundPermissions = permission.getForegroundPermissions();
+
+ int numForegroundPermissions = foregroundPermissions.size();
+ for (int i = 0; i < numForegroundPermissions; i++) {
+ Permission foregroundPermission = foregroundPermissions.get(i);
+ if (foregroundPermission.isAppOpAllowed()) {
+ wasChanged |= setAppOpMode(foregroundPermission.getAppOp(), uid, MODE_ALLOWED);
+ }
+ }
+ } else {
+ if (permission.hasBackgroundPermission()) {
+ Permission backgroundPermission = permission.getBackgroundPermission();
+
+ if (backgroundPermission == null) {
+ // The app requested a permission that has a background permission but it did
+ // not request the background permission, hence it can never get background
+ // access
+ wasChanged = setAppOpMode(permission.getAppOp(), uid, MODE_FOREGROUND);
+ } else {
+ if (backgroundPermission.isAppOpAllowed()) {
+ wasChanged = setAppOpMode(permission.getAppOp(), uid, MODE_ALLOWED);
+ } else {
+ wasChanged = setAppOpMode(permission.getAppOp(), uid, MODE_FOREGROUND);
+ }
+ }
+ } else {
+ wasChanged = setAppOpMode(permission.getAppOp(), uid, MODE_ALLOWED);
+ }
+ }
+
+ return wasChanged;
+ }
+
+ /**
+ * Kills the app the permissions belong to (and all apps sharing the same uid)
+ *
+ * @param reason The reason why the apps are killed
+ */
+ private void killApp(String reason) {
+ mActivityManager.killUid(mPackageInfo.applicationInfo.uid, reason);
+ }
+
+ /**
+ * Grant permissions of the group.
+ *
+ * <p>This also automatically grants all app ops for permissions that have app ops.
+ * <p>This does <u>only</u> grant permissions in {@link #mPermissions}, i.e. usually not
+ * the background permissions.
+ *
+ * @param setByTheUser If the user has made the decision. This does not unset the flag
+ * @param fixedByTheUser If the user requested that she/he does not want to be asked again
+ * @param filterPermissions If {@code null} all permissions of the group will be granted.
+ * Otherwise only permissions in {@code filterPermissions} will be
+ * granted.
+ *
+ * @return {@code true} iff all permissions of this group could be granted.
+ */
+ public boolean grantRuntimePermissions(boolean setByTheUser, boolean fixedByTheUser,
+ String[] filterPermissions) {
+ boolean killApp = false;
+ boolean wasAllGranted = true;
+
+ // We toggle permissions only to apps that support runtime
+ // permissions, otherwise we toggle the app op corresponding
+ // to the permission if the permission is granted to the app.
+ for (Permission permission : mPermissions.values()) {
+ if (filterPermissions != null
+ && !ArrayUtils.contains(filterPermissions, permission.getName())) {
+ continue;
+ }
+
+ if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) {
+ // Skip unallowed permissions.
+ continue;
+ }
+
+ boolean wasGranted = permission.isGrantedIncludingAppOp();
+
+ if (mAppSupportsRuntimePermissions) {
+ // Do not touch permissions fixed by the system.
+ if (permission.isSystemFixed()) {
+ wasAllGranted = false;
+ break;
+ }
+
+ // Ensure the permission app op is enabled before the permission grant.
+ if (permission.affectsAppOp() && !permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
+ }
+
+ // Grant the permission if needed.
+ if (!permission.isGranted()) {
+ permission.setGranted(true);
+ }
+
+ // Update the permission flags.
+ if (!fixedByTheUser) {
+ if (permission.isUserFixed()) {
+ permission.setUserFixed(false);
+ }
+ if (setByTheUser) {
+ if (!permission.isUserSet()) {
+ permission.setUserSet(true);
+ }
+ }
+ } else {
+ if (!permission.isUserFixed()) {
+ permission.setUserFixed(true);
+ }
+ if (permission.isUserSet()) {
+ permission.setUserSet(false);
+ }
+ }
+ if (permission.isReviewRequired()) {
+ permission.unsetReviewRequired();
+ }
+ } else {
+ // Legacy apps cannot have a not granted permission but just in case.
+ if (!permission.isGranted()) {
+ continue;
+ }
+
+ // If the permissions has no corresponding app op, then it is a
+ // third-party one and we do not offer toggling of such permissions.
+ if (permission.affectsAppOp()) {
+ if (!permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
+
+ // Legacy apps do not know that they have to retry access to a
+ // resource due to changes in runtime permissions (app ops in this
+ // case). Therefore, we restart them on app op change, so they
+ // can pick up the change.
+ killApp = true;
+ }
+
+ // Mark that the permission is not kept granted only for compatibility.
+ if (permission.isRevokedCompat()) {
+ permission.setRevokedCompat(false);
+ }
+ }
+
+ // Granting a permission explicitly means the user already
+ // reviewed it so clear the review flag on every grant.
+ if (permission.isReviewRequired()) {
+ permission.unsetReviewRequired();
+ }
+ }
+
+ // If we newly grant background access to the fine location, double-guess the user some
+ // time later if this was really the right choice.
+ if (!wasGranted && permission.isGrantedIncludingAppOp()) {
+ if (permission.getName().equals(ACCESS_FINE_LOCATION)) {
+ Permission bgPerm = permission.getBackgroundPermission();
+ if (bgPerm != null) {
+ if (bgPerm.isGrantedIncludingAppOp()) {
+ mTriggerLocationAccessCheckOnPersist = true;
+ }
+ }
+ } else if (permission.getName().equals(ACCESS_BACKGROUND_LOCATION)) {
+ ArrayList<Permission> fgPerms = permission.getForegroundPermissions();
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ Permission fgPerm = fgPerms.get(fgPermNum);
+
+ if (fgPerm.getName().equals(ACCESS_FINE_LOCATION)) {
+ if (fgPerm.isGrantedIncludingAppOp()) {
+ mTriggerLocationAccessCheckOnPersist = true;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+
+ if (killApp) {
+ killApp(KILL_REASON_APP_OP_CHANGE);
+ }
+ }
+
+ return wasAllGranted;
+ }
+
+ boolean revokeRuntimePermissions(boolean fixedByTheUser) {
+ return revokeRuntimePermissions(fixedByTheUser, null);
+ }
+
+ /**
+ * Disallow the app op for a permission/uid.
+ *
+ * <p>There are three cases:
+ * <dl>
+ * <dt>The permission is not split into foreground/background</dt>
+ * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd>
+ * <dt>The permission is a foreground permission:</dt>
+ * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd>
+ * <dt>The permission is a background permission:</dt>
+ * <dd>All granted foreground permissions for this background permission will be set to
+ * {@link AppOpsManager#MODE_FOREGROUND}</dd>
+ * </dl>
+ *
+ * @param permission The permission which has an appOps that should be disallowed
+ * @param uid The uid of the process the app op if for
+ *
+ * @return {@code true} iff app-op was changed
+ */
+ private boolean disallowAppOp(Permission permission, int uid) {
+ boolean wasChanged = false;
+
+ if (permission.isBackgroundPermission()) {
+ ArrayList<Permission> foregroundPermissions = permission.getForegroundPermissions();
+
+ int numForegroundPermissions = foregroundPermissions.size();
+ for (int i = 0; i < numForegroundPermissions; i++) {
+ Permission foregroundPermission = foregroundPermissions.get(i);
+ if (foregroundPermission.isAppOpAllowed()) {
+ wasChanged |= setAppOpMode(foregroundPermission.getAppOp(), uid,
+ MODE_FOREGROUND);
+ }
+ }
+ } else {
+ wasChanged = setAppOpMode(permission.getAppOp(), uid, MODE_IGNORED);
+ }
+
+ return wasChanged;
+ }
+
+ /**
+ * Revoke permissions of the group.
+ *
+ * <p>This also disallows all app ops for permissions that have app ops.
+ * <p>This does <u>only</u> revoke permissions in {@link #mPermissions}, i.e. usually not
+ * the background permissions.
+ *
+ * @param fixedByTheUser If the user requested that she/he does not want to be asked again
+ * @param filterPermissions If {@code null} all permissions of the group will be revoked.
+ * Otherwise only permissions in {@code filterPermissions} will be
+ * revoked.
+ *
+ * @return {@code true} iff all permissions of this group could be revoked.
+ */
+ public boolean revokeRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
+ boolean killApp = false;
+ boolean wasAllRevoked = true;
+
+ // We toggle permissions only to apps that support runtime
+ // permissions, otherwise we toggle the app op corresponding
+ // to the permission if the permission is granted to the app.
+ for (Permission permission : mPermissions.values()) {
+ if (filterPermissions != null
+ && !ArrayUtils.contains(filterPermissions, permission.getName())) {
+ continue;
+ }
+
+ // Do not touch permissions fixed by the system.
+ if (permission.isSystemFixed()) {
+ wasAllRevoked = false;
+ break;
+ }
+
+ if (mAppSupportsRuntimePermissions) {
+ // Revoke the permission if needed.
+ if (permission.isGranted()) {
+ permission.setGranted(false);
+ }
+
+ // Update the permission flags.
+ if (fixedByTheUser) {
+ // Take a note that the user fixed the permission.
+ if (permission.isUserSet() || !permission.isUserFixed()) {
+ permission.setUserSet(false);
+ permission.setUserFixed(true);
+ }
+ } else {
+ if (!permission.isUserSet() || permission.isUserFixed()) {
+ permission.setUserSet(true);
+ permission.setUserFixed(false);
+ }
+ }
+
+ if (permission.affectsAppOp()) {
+ permission.setAppOpAllowed(false);
+ }
+ } else {
+ // Legacy apps cannot have a non-granted permission but just in case.
+ if (!permission.isGranted()) {
+ continue;
+ }
+
+ // If the permission has no corresponding app op, then it is a
+ // third-party one and we do not offer toggling of such permissions.
+ if (permission.affectsAppOp()) {
+ if (permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(false);
+
+ // Disabling an app op may put the app in a situation in which it
+ // has a handle to state it shouldn't have, so we have to kill the
+ // app. This matches the revoke runtime permission behavior.
+ killApp = true;
+ }
+
+ // Mark that the permission is kept granted only for compatibility.
+ if (!permission.isRevokedCompat()) {
+ permission.setRevokedCompat(true);
+ }
+ }
+ }
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+
+ if (killApp) {
+ killApp(KILL_REASON_APP_OP_CHANGE);
+ }
+ }
+
+ return wasAllRevoked;
+ }
+
+ /**
+ * Mark permissions in this group as policy fixed.
+ *
+ * @param filterPermissions The permissions to mark
+ */
+ public void setPolicyFixed(@NonNull String[] filterPermissions) {
+ for (String permissionName : filterPermissions) {
+ Permission permission = mPermissions.get(permissionName);
+
+ if (permission != null) {
+ permission.setPolicyFixed(true);
+ }
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+ }
+ }
+
+ /**
+ * Set the user-fixed flag for all permissions in this group.
+ *
+ * @param isUsedFixed if the flag should be set or not
+ */
+ public void setUserFixed(boolean isUsedFixed) {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ permission.setUserFixed(isUsedFixed);
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+ }
+ }
+
+ /**
+ * Mark this group as having been self-revoked.
+ */
+ public void setSelfRevoked() {
+ mIsSelfRevoked = true;
+ }
+
+ /**
+ * Set the one-time flag for all permissions in this group.
+ *
+ * @param isOneTime if the flag should be set or not
+ */
+ public void setOneTime(boolean isOneTime) {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ permission.setOneTime(isOneTime);
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+ }
+ }
+
+ /**
+ * Set the user-set flag for all permissions in this group.
+ *
+ * @param isUserSet if the flag should be set or not
+ */
+ public void setUserSet(boolean isUserSet) {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ permission.setUserSet(isUserSet);
+ }
+
+ if (!mDelayChanges) {
+ persistChanges(false);
+ }
+ }
+
+ /**
+ * Get all permissions in the group.
+ */
+ public ArrayList<Permission> getPermissions() {
+ return new ArrayList<>(mPermissions.values());
+ }
+
+ /**
+ * @return An {@link AppPermissionGroup}-object that contains all background permissions for
+ * this group.
+ */
+ public AppPermissionGroup getBackgroundPermissions() {
+ return mBackgroundPermissions;
+ }
+
+ /**
+ * @return {@code true} iff the app request at least one permission in this group that has a
+ * background permission. It is possible that the app does not request the matching background
+ * permission and hence will only ever get foreground access, never background access.
+ */
+ public boolean hasPermissionWithBackgroundMode() {
+ return mHasPermissionWithBackgroundMode;
+ }
+
+ /**
+ * Is the group a storage permission group that is referring to an app that does not have
+ * isolated storage
+ *
+ * @return {@code true} iff this is a storage group on an app that does not have isolated
+ * storage
+ */
+ public boolean isNonIsolatedStorage() {
+ return mIsNonIsolatedStorage;
+ }
+
+ /**
+ * Whether this is group that contains all the background permission for regular permission
+ * group.
+ *
+ * @return {@code true} iff this is a background permission group.
+ *
+ * @see #getBackgroundPermissions()
+ */
+ public boolean isBackgroundGroup() {
+ return mPermissions.valueAt(0).isBackgroundPermission();
+ }
+
+ /**
+ * Whether this group supports one-time permissions
+ * @return {@code true} iff this group supports one-time permissions
+ */
+ public boolean supportsOneTimeGrant() {
+ return Utils.supportsOneTimeGrant(getName());
+ }
+
+ int getFlags() {
+ int flags = 0;
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ flags |= permission.getFlags();
+ }
+ return flags;
+ }
+
+ boolean isUserFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isUserFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if there's a permission in the group is policy fixed.
+ */
+ public boolean isPolicyFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isPolicyFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean isUserSet() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isUserSet()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if there's a permission in the group is system fixed.
+ */
+ public boolean isSystemFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isSystemFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return Whether any of the permissions in this group is one-time
+ */
+ public boolean isOneTime() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isOneTime()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return Whether at least one permission is granted and every granted permission is one-time
+ */
+ public boolean isStrictlyOneTime() {
+ boolean oneTimePermissionFound = false;
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isGranted()) {
+ if (!permission.isOneTime()) {
+ return false;
+ }
+ oneTimePermissionFound = true;
+ }
+ }
+ return oneTimePermissionFound;
+ }
+
+ @Override
+ public int compareTo(AppPermissionGroup another) {
+ final int result = mCollator.compare(mLabel.toString(), another.mLabel.toString());
+ if (result == 0) {
+ // Unbadged before badged.
+ return mPackageInfo.applicationInfo.uid
+ - another.mPackageInfo.applicationInfo.uid;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof AppPermissionGroup)) {
+ return false;
+ }
+
+ AppPermissionGroup other = (AppPermissionGroup) o;
+
+ boolean equal = mName.equals(other.mName)
+ && mPackageInfo.packageName.equals(other.mPackageInfo.packageName)
+ && mUserHandle.equals(other.mUserHandle)
+ && mPermissions.equals(other.mPermissions);
+ if (!equal) {
+ return false;
+ }
+
+ if (mBackgroundPermissions != null && other.getBackgroundPermissions() != null) {
+ return mBackgroundPermissions.getPermissions().equals(
+ other.getBackgroundPermissions().getPermissions());
+ }
+ return mBackgroundPermissions == other.getBackgroundPermissions();
+ }
+
+ @Override
+ public int hashCode() {
+ ArrayList<Permission> backgroundPermissions = new ArrayList<>();
+ if (mBackgroundPermissions != null) {
+ backgroundPermissions = mBackgroundPermissions.getPermissions();
+ }
+ return Objects.hash(mName, mPackageInfo.packageName, mUserHandle, mPermissions,
+ backgroundPermissions);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getClass().getSimpleName());
+ builder.append("{name=").append(mName);
+ if (mBackgroundPermissions != null) {
+ builder.append(", <has background permissions>}");
+ }
+ if (!mPermissions.isEmpty()) {
+ builder.append(", <has permissions>}");
+ } else {
+ builder.append('}');
+ }
+ return builder.toString();
+ }
+
+ private void addPermission(Permission permission) {
+ mPermissions.put(permission.getName(), permission);
+ if (permission.isEphemeral()) {
+ mContainsEphemeralPermission = true;
+ }
+ if (!permission.isRuntimeOnly()) {
+ mContainsPreRuntimePermission = true;
+ }
+ }
+
+ /**
+ * If the changes to this group were delayed, persist them to the platform.
+ *
+ * @param mayKillBecauseOfAppOpsChange If the app these permissions belong to may be killed if
+ * app ops change. If this is set to {@code false} the
+ * caller has to make sure to kill the app if needed.
+ */
+ public void persistChanges(boolean mayKillBecauseOfAppOpsChange) {
+ persistChanges(mayKillBecauseOfAppOpsChange, null, null);
+ }
+
+ /**
+ * If the changes to this group were delayed, persist them to the platform.
+ *
+ * @param mayKillBecauseOfAppOpsChange If the app these permissions belong to may be killed if
+ * app ops change. If this is set to {@code false} the
+ * caller has to make sure to kill the app if needed.
+ * @param revokeReason If any permissions are getting revoked, the reason for revoking them.
+ */
+ public void persistChanges(boolean mayKillBecauseOfAppOpsChange, String revokeReason) {
+ persistChanges(mayKillBecauseOfAppOpsChange, revokeReason, null);
+ }
+
+ /**
+ * If the changes to this group were delayed, persist them to the platform.
+ *
+ * @param mayKillBecauseOfAppOpsChange If the app these permissions belong to may be killed if
+ * app ops change. If this is set to {@code false} the
+ * caller has to make sure to kill the app if needed.
+ * @param revokeReason If any permissions are getting revoked, the reason for revoking them.
+ * @param filterPermissions If provided, only persist state for the given permissions
+ */
+ public void persistChanges(boolean mayKillBecauseOfAppOpsChange, String revokeReason,
+ Set<String> filterPermissions) {
+ int uid = mPackageInfo.applicationInfo.uid;
+
+ int numPermissions = mPermissions.size();
+ boolean shouldKillApp = false;
+
+ for (int i = 0; i < numPermissions; i++) {
+ Permission permission = mPermissions.valueAt(i);
+
+ if (filterPermissions != null && !filterPermissions.contains(permission.getName())) {
+ continue;
+ }
+
+ if (!permission.isSystemFixed()) {
+ if (permission.isGranted()) {
+ mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), mUserHandle);
+ } else {
+ boolean isCurrentlyGranted = mContext.checkPermission(permission.getName(), -1,
+ uid) == PERMISSION_GRANTED;
+
+ if (isCurrentlyGranted) {
+ if (revokeReason == null) {
+ mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), mUserHandle);
+ } else {
+ mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), mUserHandle, revokeReason);
+ }
+ }
+ }
+ }
+
+// int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0)
+// | (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0)
+// | (permission.isRevokedCompat()
+// ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0)
+// | (permission.isPolicyFixed() ?
+// PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0)
+// | (permission.isReviewRequired()
+// ? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0)
+// | (permission.isOneTime() ? PackageManager.FLAG_PERMISSION_ONE_TIME : 0)
+// | (permission.isSelectedLocationAccuracy()
+// ? PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY : 0);
+
+// mPackageManager.updatePermissionFlags(permission.getName(),
+// mPackageInfo.packageName,
+// PackageManager.FLAG_PERMISSION_USER_SET
+// | PackageManager.FLAG_PERMISSION_USER_FIXED
+// | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
+// | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+// | (permission.isReviewRequired()
+// ? 0 : PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED)
+// | PackageManager.FLAG_PERMISSION_ONE_TIME
+// | PackageManager.FLAG_PERMISSION_AUTO_REVOKED // clear auto revoke
+// | PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY,
+// flags, mUserHandle);
+
+ if (permission.affectsAppOp()) {
+ if (!permission.isSystemFixed()) {
+ // Enabling/Disabling an app op may put the app in a situation in which it has
+ // a handle to state it shouldn't have, so we have to kill the app. This matches
+ // the revoke runtime permission behavior.
+ if (permission.isAppOpAllowed()) {
+ boolean wasChanged = allowAppOp(permission, uid);
+ shouldKillApp |= wasChanged && !mAppSupportsRuntimePermissions;
+ } else {
+ shouldKillApp |= disallowAppOp(permission, uid);
+ }
+ }
+ }
+ }
+
+ if (mayKillBecauseOfAppOpsChange && shouldKillApp) {
+ killApp(KILL_REASON_APP_OP_CHANGE);
+ }
+
+// if (mTriggerLocationAccessCheckOnPersist) {
+// new LocationAccessCheck(mContext, null).checkLocationAccessSoon();
+// mTriggerLocationAccessCheckOnPersist = false;
+// }
+
+// String packageName = mPackageInfo.packageName;
+// if (areRuntimePermissionsGranted(null, true, false)) {
+// // Required to read device config in Utils.getOneTimePermissions*().
+// final long token = Binder.clearCallingIdentity();
+// try {
+// if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+// mContext.getSystemService(PermissionManager.class)
+// .startOneTimePermissionSession(packageName,
+// Utils.getOneTimePermissionsTimeout(),
+// Utils.getOneTimePermissionsKilledDelay(mIsSelfRevoked),
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE);
+// } else {
+// mContext.getSystemService(PermissionManager.class)
+// .startOneTimePermissionSession(packageName,
+// Utils.getOneTimePermissionsTimeout(),
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
+// ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE);
+// }
+// } finally {
+// Binder.restoreCallingIdentity(token);
+// }
+// } else {
+// mContext.getSystemService(PermissionManager.class)
+// .stopOneTimePermissionSession(packageName);
+// }
+ }
+
+ /**
+ * Check if permission group contains a runtime permission that split from an installed
+ * permission and the split happened in an Android version higher than app's targetSdk.
+ *
+ * @return {@code true} if there is such permission, {@code false} otherwise
+ */
+ public boolean hasInstallToRuntimeSplit() {
+ PermissionManager permissionManager =
+ (PermissionManager) mContext.getSystemService(PermissionManager.class);
+
+ int numSplitPerms = permissionManager.getSplitPermissions().size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ PermissionManager.SplitPermissionInfo spi =
+ permissionManager.getSplitPermissions().get(splitPermNum);
+ String splitPerm = spi.getSplitPermission();
+
+ PermissionInfo pi;
+ try {
+ pi = mPackageManager.getPermissionInfo(splitPerm, 0);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "No such permission: " + splitPerm, e);
+ continue;
+ }
+
+ // Skip if split permission is not "install" permission.
+ if (pi.getProtection() != pi.PROTECTION_NORMAL) {
+ continue;
+ }
+
+ List<String> newPerms = spi.getNewPermissions();
+ int numNewPerms = newPerms.size();
+ for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
+ String newPerm = newPerms.get(newPermNum);
+
+ if (!hasPermission(newPerm)) {
+ continue;
+ }
+
+ try {
+ pi = mPackageManager.getPermissionInfo(newPerm, 0);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "No such permission: " + newPerm, e);
+ continue;
+ }
+
+ // Skip if new permission is not "runtime" permission.
+ if (pi.getProtection() != pi.PROTECTION_DANGEROUS) {
+ continue;
+ }
+
+ if (mPackageInfo.applicationInfo.targetSdkVersion < spi.getTargetSdk()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissions.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissions.java
new file mode 100644
index 000000000000..9ef8d532dbfc
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/AppPermissions.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.model;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An app that requests permissions.
+ *
+ * <p>Allows to query all permission groups of the app and which permission belongs to which group.
+ */
+public final class AppPermissions {
+ /**
+ * All permission groups the app requests. Background permission groups are attached to their
+ * foreground groups.
+ */
+ private final ArrayList<AppPermissionGroup> mGroups = new ArrayList<>();
+
+ /** Cache: group name -> group */
+ private final ArrayMap<String, AppPermissionGroup> mGroupNameToGroup = new ArrayMap<>();
+
+ /** Cache: permission name -> group. Might point to background group */
+ private final ArrayMap<String, AppPermissionGroup> mPermissionNameToGroup = new ArrayMap<>();
+
+ private final Context mContext;
+
+ private final CharSequence mAppLabel;
+
+ private final Runnable mOnErrorCallback;
+
+ private final boolean mSortGroups;
+
+ /** Do not actually commit changes to the platform until {@link #persistChanges} is called */
+ private final boolean mDelayChanges;
+
+ private PackageInfo mPackageInfo;
+
+ public AppPermissions(Context context, PackageInfo packageInfo, boolean sortGroups,
+ Runnable onErrorCallback) {
+ this(context, packageInfo, sortGroups, false, onErrorCallback);
+ }
+
+ public AppPermissions(Context context, PackageInfo packageInfo, boolean sortGroups,
+ boolean delayChanges, Runnable onErrorCallback) {
+ mContext = context;
+ mPackageInfo = packageInfo;
+ mAppLabel = null; // doesn't matter for CDM
+ mSortGroups = sortGroups;
+ mDelayChanges = delayChanges;
+ mOnErrorCallback = onErrorCallback;
+ loadPermissionGroups();
+ }
+
+ public PackageInfo getPackageInfo() {
+ return mPackageInfo;
+ }
+
+ /**
+ * Refresh package info and permission groups.
+ */
+ public void refresh() {
+ loadPackageInfo();
+ loadPermissionGroups();
+ }
+
+ public CharSequence getAppLabel() {
+ return mAppLabel;
+ }
+
+ /**
+ * Get permission group by name.
+ */
+ public AppPermissionGroup getPermissionGroup(String name) {
+ return mGroupNameToGroup.get(name);
+ }
+
+ public List<AppPermissionGroup> getPermissionGroups() {
+ return mGroups;
+ }
+
+ /**
+ * Check if the group is review required.
+ */
+ public boolean isReviewRequired() {
+ final int groupCount = mGroups.size();
+ for (int i = 0; i < groupCount; i++) {
+ AppPermissionGroup group = mGroups.get(i);
+ if (group.isReviewRequired()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void loadPackageInfo() {
+ try {
+ mPackageInfo = mContext.createPackageContextAsUser(mPackageInfo.packageName, 0,
+ UserHandle.getUserHandleForUid(mPackageInfo.applicationInfo.uid))
+ .getPackageManager().getPackageInfo(mPackageInfo.packageName,
+ PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (mOnErrorCallback != null) {
+ mOnErrorCallback.run();
+ }
+ }
+ }
+
+ /**
+ * Add all individual permissions of the {@code group} to the {@link #mPermissionNameToGroup}
+ * lookup table.
+ *
+ * @param group The group of permissions to add
+ */
+ private void addAllPermissions(AppPermissionGroup group) {
+ ArrayList<Permission> perms = group.getPermissions();
+
+ int numPerms = perms.size();
+ for (int permNum = 0; permNum < numPerms; permNum++) {
+ mPermissionNameToGroup.put(perms.get(permNum).getName(), group);
+ }
+ }
+
+ private void loadPermissionGroups() {
+ mGroups.clear();
+ mGroupNameToGroup.clear();
+ mPermissionNameToGroup.clear();
+
+ if (mPackageInfo.requestedPermissions != null) {
+ for (String requestedPerm : mPackageInfo.requestedPermissions) {
+ if (getGroupForPermission(requestedPerm) == null) {
+ AppPermissionGroup group = AppPermissionGroup.create(mContext, mPackageInfo,
+ requestedPerm, mDelayChanges);
+ if (group == null) {
+ continue;
+ }
+
+ mGroups.add(group);
+ mGroupNameToGroup.put(group.getName(), group);
+
+ addAllPermissions(group);
+
+ AppPermissionGroup backgroundGroup = group.getBackgroundPermissions();
+ if (backgroundGroup != null) {
+ addAllPermissions(backgroundGroup);
+ }
+ }
+ }
+
+ if (mSortGroups) {
+ Collections.sort(mGroups);
+ }
+ }
+ }
+
+ /**
+ * Find the group a permission belongs to.
+ *
+ * <p>The group found might be a background group.
+ *
+ * @param permission The name of the permission
+ *
+ * @return The group the permission belongs to
+ */
+ public AppPermissionGroup getGroupForPermission(String permission) {
+ return mPermissionNameToGroup.get(permission);
+ }
+
+ /**
+ * If the changes to the permission groups were delayed, persist them now.
+ *
+ * @param mayKillBecauseOfAppOpsChange If the app may be killed if app ops change. If this is
+ * set to {@code false} the caller has to make sure to kill
+ * the app if needed.
+ */
+ public void persistChanges(boolean mayKillBecauseOfAppOpsChange) {
+ persistChanges(mayKillBecauseOfAppOpsChange, null);
+ }
+
+ /**
+ * If the changes to the permission groups were delayed, persist them now.
+ *
+ * @param mayKillBecauseOfAppOpsChange If the app may be killed if app ops change. If this is
+ * set to {@code false} the caller has to make sure to kill
+ * the app if needed.
+ * @param filterPermissions If provided, only persist state for the given permissions
+ */
+ public void persistChanges(boolean mayKillBecauseOfAppOpsChange,
+ Set<String> filterPermissions) {
+ if (mDelayChanges) {
+ int numGroups = mGroups.size();
+
+ for (int i = 0; i < numGroups; i++) {
+ AppPermissionGroup group = mGroups.get(i);
+ group.persistChanges(mayKillBecauseOfAppOpsChange, null, filterPermissions);
+
+ AppPermissionGroup backgroundGroup = group.getBackgroundPermissions();
+ if (backgroundGroup != null) {
+ backgroundGroup.persistChanges(mayKillBecauseOfAppOpsChange, null,
+ filterPermissions);
+ }
+ }
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/Permission.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/Permission.java
new file mode 100644
index 000000000000..2bec970a1dea
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/model/Permission.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.model;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * A permission and its properties.
+ *
+ * @see AppPermissionGroup
+ */
+public final class Permission {
+ private final @NonNull PermissionInfo mPermissionInfo;
+ private final String mName;
+ private final String mBackgroundPermissionName;
+ private final String mAppOp;
+
+ private boolean mGranted;
+ private boolean mAppOpAllowed;
+ private int mFlags;
+ private boolean mIsEphemeral;
+ private boolean mIsRuntimeOnly;
+ private Permission mBackgroundPermission;
+ private ArrayList<Permission> mForegroundPermissions;
+ private boolean mWhitelisted;
+
+ public Permission(String name, @NonNull PermissionInfo permissionInfo, boolean granted,
+ String appOp, boolean appOpAllowed, int flags) {
+ mPermissionInfo = permissionInfo;
+ mName = name;
+ mBackgroundPermissionName = permissionInfo.backgroundPermission;
+ mGranted = granted;
+ mAppOp = appOp;
+ mAppOpAllowed = appOpAllowed;
+ mFlags = flags;
+ mIsEphemeral =
+ (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
+ mIsRuntimeOnly =
+ (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
+ }
+
+ /**
+ * Mark this permission as background permission for {@code foregroundPermissions}.
+ *
+ * @param foregroundPermission The foreground permission
+ */
+ public void addForegroundPermissions(Permission foregroundPermission) {
+ if (mForegroundPermissions == null) {
+ mForegroundPermissions = new ArrayList<>(1);
+ }
+ mForegroundPermissions.add(foregroundPermission);
+ }
+
+ /**
+ * Mark this permission as foreground permission for {@code backgroundPermission}.
+ *
+ * @param backgroundPermission The background permission
+ */
+ public void setBackgroundPermission(Permission backgroundPermission) {
+ mBackgroundPermission = backgroundPermission;
+ }
+
+ public PermissionInfo getPermissionInfo() {
+ return mPermissionInfo;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getAppOp() {
+ return mAppOp;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ boolean isHardRestricted() {
+ return (mPermissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+ }
+
+ boolean isSoftRestricted() {
+ return (mPermissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+ }
+
+ /**
+ * Does this permission affect app ops.
+ *
+ * <p>I.e. does this permission have a matching app op or is this a background permission. All
+ * background permissions affect the app op of its assigned foreground permission.
+ *
+ * @return {@code true} if this permission affects app ops
+ */
+ public boolean affectsAppOp() {
+ return mAppOp != null || isBackgroundPermission();
+ }
+
+ /**
+ * Check if the permission is granted.
+ *
+ * <p>This ignores the state of the app-op. I.e. for apps not handling runtime permissions, this
+ * always returns {@code true}.
+ *
+ * @return If the permission is granted
+ */
+ public boolean isGranted() {
+ return mGranted;
+ }
+
+ /**
+ * Check if the permission is granted, also considering the state of the app-op.
+ *
+ * <p>For the UI, check the grant state of the whole group via
+ * {@link AppPermissionGroup#areRuntimePermissionsGranted}.
+ *
+ * @return {@code true} if the permission (and the app-op) is granted.
+ */
+ public boolean isGrantedIncludingAppOp() {
+ return mGranted && (!affectsAppOp() || isAppOpAllowed()) && !isReviewRequired();
+ }
+
+ public boolean isReviewRequired() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
+ }
+
+ /**
+ * Unset review required flag.
+ */
+ public void unsetReviewRequired() {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+
+ public void setGranted(boolean mGranted) {
+ this.mGranted = mGranted;
+ }
+
+ public boolean isAppOpAllowed() {
+ return mAppOpAllowed;
+ }
+
+ /**
+ * Check if it's user fixed.
+ */
+ public boolean isUserFixed() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0;
+ }
+
+ /**
+ * Set user fixed flag.
+ */
+ public void setUserFixed(boolean userFixed) {
+ if (userFixed) {
+ mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED;
+ }
+ }
+
+ /**
+ * Sets the one-time permission flag
+ * @param oneTime true to set the flag, false to unset it
+ */
+ public void setOneTime(boolean oneTime) {
+ if (oneTime) {
+ mFlags |= PackageManager.FLAG_PERMISSION_ONE_TIME;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_ONE_TIME;
+ }
+ }
+
+ public boolean isSelectedLocationAccuracy() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY) != 0;
+ }
+
+ /**
+ * Sets the selected-location-accuracy permission flag
+ * @param selectedLocationAccuracy true to set the flag, false to unset it
+ */
+ public void setSelectedLocationAccuracy(boolean selectedLocationAccuracy) {
+ if (selectedLocationAccuracy) {
+ mFlags |= PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
+ }
+ }
+
+ public boolean isSystemFixed() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
+ }
+
+ public boolean isPolicyFixed() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
+ }
+
+ public boolean isUserSet() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+ }
+
+ public boolean isGrantedByDefault() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
+ }
+
+ /**
+ * Is the permission user sensitive, i.e. should it always be shown to the user.
+ *
+ * <p>Non-sensitive permission are usually hidden behind a setting in an overflow menu or
+ * some other kind of flag.
+ *
+ * @return {@code true} if the permission is user sensitive.
+ */
+ public boolean isUserSensitive() {
+ if (isGrantedIncludingAppOp()) {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
+ } else {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0;
+ }
+ }
+
+ /**
+ * If this permission is split into a foreground and background permission, this is the name
+ * of the background permission.
+ *
+ * @return The name of the background permission or {@code null} if the permission is not split
+ */
+ public String getBackgroundPermissionName() {
+ return mBackgroundPermissionName;
+ }
+
+ /**
+ * @return If this permission is split into a foreground and background permission,
+ * returns the background permission
+ */
+ public Permission getBackgroundPermission() {
+ return mBackgroundPermission;
+ }
+
+ /**
+ * @return If this permission is split into a foreground and background permission,
+ * returns the foreground permission
+ */
+ public ArrayList<Permission> getForegroundPermissions() {
+ return mForegroundPermissions;
+ }
+
+ /**
+ * @return {@code true} iff this is the foreground permission of a background-foreground-split
+ * permission
+ */
+ public boolean hasBackgroundPermission() {
+ return mBackgroundPermissionName != null;
+ }
+
+ /**
+ * @return {@code true} iff this is the background permission of a background-foreground-split
+ * permission
+ */
+ public boolean isBackgroundPermission() {
+ return mForegroundPermissions != null;
+ }
+
+ /**
+ * @see PackageManager#FLAG_PERMISSION_ONE_TIME
+ */
+ public boolean isOneTime() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_ONE_TIME) != 0;
+ }
+
+ /**
+ * Set userSet flag.
+ */
+ public void setUserSet(boolean userSet) {
+ if (userSet) {
+ mFlags |= PackageManager.FLAG_PERMISSION_USER_SET;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET;
+ }
+ }
+
+ /**
+ * Set policy fixed flag.
+ */
+ public void setPolicyFixed(boolean policyFixed) {
+ if (policyFixed) {
+ mFlags |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ }
+ }
+
+ /**
+ * Check if the permission is revoke compat.
+ */
+ public boolean isRevokedCompat() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_REVOKED_COMPAT) != 0;
+ }
+
+ /**
+ * Set revoke compat flag.
+ */
+ public void setRevokedCompat(boolean revokedCompat) {
+ if (revokedCompat) {
+ mFlags |= PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
+ }
+ }
+
+ /**
+ * Set app op allowed flag.
+ */
+ public void setAppOpAllowed(boolean mAppOpAllowed) {
+ this.mAppOpAllowed = mAppOpAllowed;
+ }
+
+ /**
+ * Check if it's ephemeral.
+ */
+ public boolean isEphemeral() {
+ return mIsEphemeral;
+ }
+
+ /**
+ * Check if it's runtime only.
+ */
+ public boolean isRuntimeOnly() {
+ return mIsRuntimeOnly;
+ }
+
+ /**
+ * Check if it's granting allowed.
+ */
+ public boolean isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions) {
+ return (!isEphemeralApp || isEphemeral())
+ && (supportsRuntimePermissions || !isRuntimeOnly());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Permission)) {
+ return false;
+ }
+
+ Permission other = (Permission) o;
+
+ if (!Objects.equals(getName(), other.getName()) || getFlags() != other.getFlags()
+ || isGranted() != other.isGranted()) {
+ return false;
+ }
+
+
+ // Only compare permission names, in order to avoid recursion
+ if (getBackgroundPermission() != null && other.getBackgroundPermission() != null) {
+ if (!Objects.equals(getBackgroundPermissionName(),
+ other.getBackgroundPermissionName())) {
+ return false;
+ }
+ } else if (getBackgroundPermission() != other.getBackgroundPermission()) {
+ return false;
+ }
+
+ if (getForegroundPermissions() != null && other.getForegroundPermissions() != null) {
+ ArrayList<Permission> others = other.getForegroundPermissions();
+ if (getForegroundPermissions().size() != others.size()) {
+ return false;
+ }
+ for (int i = 0; i < others.size(); i++) {
+ if (!getForegroundPermissions().get(i).getName().equals(others.get(i).getName())) {
+ return false;
+ }
+ }
+ } else if (getForegroundPermissions() != null || other.getForegroundPermissions() != null) {
+ return false;
+ }
+
+ return Objects.equals(getAppOp(), other.getAppOp())
+ && isAppOpAllowed() == other.isAppOpAllowed();
+ }
+
+ @Override
+ public int hashCode() {
+ ArrayList<String> linkedPermissionNames = new ArrayList<>();
+ if (mBackgroundPermission != null) {
+ linkedPermissionNames.add(mBackgroundPermission.getName());
+ }
+ if (mForegroundPermissions != null) {
+ for (Permission linkedPermission: mForegroundPermissions) {
+ if (linkedPermission != null) {
+ linkedPermissionNames.add(linkedPermission.getName());
+ }
+ }
+ }
+ return Objects.hash(mName, mFlags, mGranted, mAppOp, mAppOpAllowed, linkedPermissionNames);
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/ArrayUtils.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/ArrayUtils.java
new file mode 100644
index 000000000000..7027528fc203
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/ArrayUtils.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.utils;
+
+import android.annotation.Nullable;
+
+import java.util.Objects;
+
+/**
+ * Utils for array manipulation.
+ */
+public final class ArrayUtils {
+ private ArrayUtils() { /* cannot be instantiated */ }
+
+ /**
+ * Checks if an array is null or has no elements.
+ *
+ * @param array the array to check for
+ *
+ * @return whether the array is null or has no elements.
+ */
+ public static <T> boolean isEmpty(@Nullable T[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks that value is present as at least one of the elements of the array.
+ * @param array the array to check in
+ * @param value the value to check for
+ * @return true if the value is present in the array
+ */
+ public static <T> boolean contains(T[] array, T value) {
+ return indexOf(array, value) != -1;
+ }
+
+ /**
+ * Return first index of {@code value} in {@code array}, or {@code -1} if
+ * not found.
+ */
+ public static <T> int indexOf(T[] array, T value) {
+ if (array == null) return -1;
+ for (int i = 0; i < array.length; i++) {
+ if (Objects.equals(array[i], value)) return i;
+ }
+ return -1;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/LocationUtils.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/LocationUtils.java
new file mode 100644
index 000000000000..9402e46d16d9
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/LocationUtils.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.utils;
+
+import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Utils for location service.
+ */
+public class LocationUtils {
+
+ public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION;
+ public static final String ACTIVITY_RECOGNITION_PERMISSION =
+ Manifest.permission_group.ACTIVITY_RECOGNITION;
+
+ private static final String TAG = LocationUtils.class.getSimpleName();
+ private static final long LOCATION_UPDATE_DELAY_MS = 1000;
+ private static final Handler sMainHandler = new Handler(Looper.getMainLooper());
+
+
+ /** Start the settings page for the location controller extra package. */
+ public static void startLocationControllerExtraPackageSettings(@NonNull Context context,
+ @NonNull UserHandle user) {
+ try {
+ context.startActivityAsUser(new Intent(
+ Settings.ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS), user);
+ } catch (ActivityNotFoundException e) {
+ // In rare cases where location controller extra package is set, but
+ // no activity exists to handle the location controller extra package settings
+ // intent, log an error instead of crashing permission controller.
+ Log.e(TAG, "No activity to handle "
+ + "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS");
+ }
+ }
+
+ /**
+ * Check if location is enabled.
+ */
+ public static boolean isLocationEnabled(Context context) {
+ return context.getSystemService(LocationManager.class).isLocationEnabled();
+ }
+
+ /** Checks if the provided package is a location provider. */
+ public static boolean isLocationProvider(Context context, String packageName) {
+ return context.getSystemService(LocationManager.class).isProviderPackage(packageName);
+ }
+
+ /**
+ * Check if group is location and the package is a location provider.
+ */
+ public static boolean isLocationGroupAndProvider(Context context, String groupName,
+ String packageName) {
+ return LOCATION_PERMISSION.equals(groupName) && isLocationProvider(context, packageName);
+ }
+
+ /**
+ * Check if group is location and package is extra location controller.
+ */
+ public static boolean isLocationGroupAndControllerExtraPackage(@NonNull Context context,
+ @NonNull String groupName, @NonNull String packageName) {
+ return (LOCATION_PERMISSION.equals(groupName)
+ || ACTIVITY_RECOGNITION_PERMISSION.equals(groupName))
+ && packageName.equals(context.getSystemService(LocationManager.class)
+ .getExtraLocationControllerPackage());
+ }
+
+ /** Returns whether the location controller extra package is enabled. */
+ public static boolean isExtraLocationControllerPackageEnabled(Context context) {
+ try {
+ return context.getSystemService(LocationManager.class)
+ .isExtraLocationControllerPackageEnabled();
+ } catch (Exception e) {
+ return false;
+ }
+
+ }
+
+ /**
+ * A Listener which responds to enabling or disabling of location on the device
+ */
+ public interface LocationListener {
+
+ /**
+ * A callback run any time we receive a broadcast stating the location enable state has
+ * changed.
+ * @param enabled Whether or not location is enabled
+ */
+ void onLocationStateChange(boolean enabled);
+ }
+
+ private static final ArrayList<LocationListener> sLocationListeners = new ArrayList<>();
+
+ private static BroadcastReceiver sLocationBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ boolean isEnabled = intent.getBooleanExtra(EXTRA_LOCATION_ENABLED, true);
+ sMainHandler.postDelayed(() -> {
+ synchronized (sLocationListeners) {
+ for (LocationListener l : sLocationListeners) {
+ l.onLocationStateChange(isEnabled);
+ }
+ }
+ }, LOCATION_UPDATE_DELAY_MS);
+ }
+ };
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/SoftRestrictedPermissionPolicy.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/SoftRestrictedPermissionPolicy.java
new file mode 100644
index 000000000000..d4940502f1e2
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/SoftRestrictedPermissionPolicy.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.utils;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.os.Build;
+
+import com.android.server.companion.datatransfer.permbackup.model.Permission;
+
+/**
+ * The behavior of soft restricted permissions is different for each permission. This class collects
+ * the policies in one place.
+ *
+ * This is the twin of {@link com.android.server.policy.SoftRestrictedPermissionPolicy}
+ */
+public abstract class SoftRestrictedPermissionPolicy {
+
+ /**
+ * Check if the permission should be shown in the UI.
+ *
+ * @param pkg the package the permission belongs to
+ * @param permission the permission
+ *
+ * @return {@code true} iff the permission should be shown in the UI.
+ */
+ public static boolean shouldShow(@NonNull PackageInfo pkg, @NonNull Permission permission) {
+ switch (permission.getName()) {
+ case READ_EXTERNAL_STORAGE:
+ case WRITE_EXTERNAL_STORAGE: {
+ boolean isWhiteListed =
+ (permission.getFlags() & Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)
+ != 0;
+ int targetSDK = pkg.applicationInfo.targetSdkVersion;
+
+ return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
+ }
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Check if the permission should be shown in the UI.
+ *
+ * @param pkg the LightPackageInfo the permission belongs to
+ * @param permissionName the name of the permission
+ * @param permissionFlags the PermissionController flags (not the PermissionInfo flags) for
+ * the permission
+ *
+ * @return {@code true} iff the permission should be shown in the UI.
+ */
+ public static boolean shouldShow(@NonNull PackageInfo pkg, @NonNull String permissionName,
+ int permissionFlags) {
+ switch (permissionName) {
+ case READ_EXTERNAL_STORAGE:
+ case WRITE_EXTERNAL_STORAGE: {
+ boolean isWhiteListed =
+ (permissionFlags & Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+ return isWhiteListed || pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.Q;
+ }
+ default:
+ return true;
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/Utils.java b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/Utils.java
new file mode 100644
index 000000000000..9350549d233e
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/datatransfer/permbackup/utils/Utils.java
@@ -0,0 +1,819 @@
+/*
+ * Copyright (C) 2022 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.companion.datatransfer.permbackup.utils;
+
+import static android.Manifest.permission_group.ACTIVITY_RECOGNITION;
+import static android.Manifest.permission_group.CALENDAR;
+import static android.Manifest.permission_group.CALL_LOG;
+import static android.Manifest.permission_group.CAMERA;
+import static android.Manifest.permission_group.CONTACTS;
+import static android.Manifest.permission_group.LOCATION;
+import static android.Manifest.permission_group.MICROPHONE;
+import static android.Manifest.permission_group.NEARBY_DEVICES;
+import static android.Manifest.permission_group.NOTIFICATIONS;
+import static android.Manifest.permission_group.PHONE;
+import static android.Manifest.permission_group.READ_MEDIA_AURAL;
+import static android.Manifest.permission_group.READ_MEDIA_VISUAL;
+import static android.Manifest.permission_group.SENSORS;
+import static android.Manifest.permission_group.SMS;
+import static android.Manifest.permission_group.STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.Application;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ResolveInfo;
+import android.hardware.SensorPrivacyManager;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.server.companion.datatransfer.permbackup.model.AppPermissionGroup;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * Util class for BackupHelper
+ */
+public final class Utils {
+
+ @Retention(SOURCE)
+ @IntDef(value = {LAST_24H_SENSOR_TODAY, LAST_24H_SENSOR_YESTERDAY,
+ LAST_24H_CONTENT_PROVIDER, NOT_IN_LAST_7D})
+ public @interface AppPermsLastAccessType {}
+ public static final int LAST_24H_SENSOR_TODAY = 1;
+ public static final int LAST_24H_SENSOR_YESTERDAY = 2;
+ public static final int LAST_24H_CONTENT_PROVIDER = 3;
+ public static final int LAST_7D_SENSOR = 4;
+ public static final int LAST_7D_CONTENT_PROVIDER = 5;
+ public static final int NOT_IN_LAST_7D = 6;
+
+ private static final List<String> SENSOR_DATA_PERMISSIONS = List.of(
+ Manifest.permission_group.LOCATION,
+ Manifest.permission_group.CAMERA,
+ Manifest.permission_group.MICROPHONE
+ );
+
+ public static final List<String> STORAGE_SUPERGROUP_PERMISSIONS =
+// (SDK_INT < Build.VERSION_CODES.TIRAMISU) ? List.of() :
+ List.of(
+ Manifest.permission_group.STORAGE,
+ Manifest.permission_group.READ_MEDIA_AURAL,
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ );
+
+ private static final String LOG_TAG = "Utils";
+
+ public static final String OS_PKG = "android";
+
+ public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
+
+ /** The time an app needs to be unused in order to be hibernated */
+ public static final String PROPERTY_HIBERNATION_UNUSED_THRESHOLD_MILLIS =
+ "auto_revoke_unused_threshold_millis2";
+
+ /** The frequency of running the job for hibernating apps */
+ public static final String PROPERTY_HIBERNATION_CHECK_FREQUENCY_MILLIS =
+ "auto_revoke_check_frequency_millis";
+
+ /** Whether hibernation targets apps that target a pre-S SDK */
+ public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS =
+ "app_hibernation_targets_pre_s_apps";
+
+ /** Whether or not app hibernation is enabled on the device **/
+ public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
+
+ /** Whether to show the Permissions Hub. */
+ private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
+
+ /** The timeout for one-time permissions */
+ private static final String PROPERTY_ONE_TIME_PERMISSIONS_TIMEOUT_MILLIS =
+ "one_time_permissions_timeout_millis";
+
+ /** The delay before ending a one-time permission session when all processes are dead */
+ private static final String PROPERTY_ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS =
+ "one_time_permissions_killed_delay_millis";
+
+ /** Whether to show location access check notifications. */
+ private static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED =
+ "location_access_check_enabled";
+
+ /** The time an app needs to be unused in order to be hibernated */
+ public static final String PROPERTY_PERMISSION_DECISIONS_CHECK_OLD_FREQUENCY_MILLIS =
+ "permission_decisions_check_old_frequency_millis";
+
+ /** The time an app needs to be unused in order to be hibernated */
+ public static final String PROPERTY_PERMISSION_DECISIONS_MAX_DATA_AGE_MILLIS =
+ "permission_decisions_max_data_age_millis";
+
+ /** Whether or not warning banner is displayed when device sensors are off **/
+ public static final String PROPERTY_WARNING_BANNER_DISPLAY_ENABLED = "warning_banner_enabled";
+
+ /** All permission whitelists. */
+ public static final int FLAGS_PERMISSION_WHITELIST_ALL =
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
+
+ /** All permission restriction exemptions. */
+ public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
+ FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+
+ /**
+ * The default length of the timeout for one-time permissions
+ */
+ public static final long ONE_TIME_PERMISSIONS_TIMEOUT_MILLIS = 1 * 60 * 1000; // 1 minute
+
+ /**
+ * The default length to wait before ending a one-time permission session after all processes
+ * are dead.
+ */
+ public static final long ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS = 5 * 1000;
+
+ /** Mapping permission -> group for all dangerous platform permissions */
+ private static final ArrayMap<String, String> PLATFORM_PERMISSIONS;
+
+ /** Mapping group -> permissions for all dangerous platform permissions */
+ private static final ArrayMap<String, ArrayList<String>> PLATFORM_PERMISSION_GROUPS;
+
+ /** Set of groups that will be able to receive one-time grant */
+ private static final ArraySet<String> ONE_TIME_PERMISSION_GROUPS;
+
+ /** Permission -> Sensor codes */
+ private static final ArrayMap<String, Integer> PERM_SENSOR_CODES;
+
+ public static final int FLAGS_ALWAYS_USER_SENSITIVE =
+ FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ | FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
+
+ private static final String SYSTEM_PKG = "android";
+
+ private static final String SYSTEM_AMBIENT_AUDIO_INTELLIGENCE =
+ "android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE";
+ private static final String SYSTEM_UI_INTELLIGENCE =
+ "android.app.role.SYSTEM_UI_INTELLIGENCE";
+ private static final String SYSTEM_AUDIO_INTELLIGENCE =
+ "android.app.role.SYSTEM_AUDIO_INTELLIGENCE";
+ private static final String SYSTEM_NOTIFICATION_INTELLIGENCE =
+ "android.app.role.SYSTEM_NOTIFICATION_INTELLIGENCE";
+ private static final String SYSTEM_TEXT_INTELLIGENCE =
+ "android.app.role.SYSTEM_TEXT_INTELLIGENCE";
+ private static final String SYSTEM_VISUAL_INTELLIGENCE =
+ "android.app.role.SYSTEM_VISUAL_INTELLIGENCE";
+
+ // TODO: theianchen Using hardcoded values here as a WIP solution for now.
+ private static final String[] EXEMPTED_ROLES = {
+ SYSTEM_AMBIENT_AUDIO_INTELLIGENCE,
+ SYSTEM_UI_INTELLIGENCE,
+ SYSTEM_AUDIO_INTELLIGENCE,
+ SYSTEM_NOTIFICATION_INTELLIGENCE,
+ SYSTEM_TEXT_INTELLIGENCE,
+ SYSTEM_VISUAL_INTELLIGENCE,
+ };
+
+ static {
+ PLATFORM_PERMISSIONS = new ArrayMap<>();
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CONTACTS, CONTACTS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CONTACTS, CONTACTS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.GET_ACCOUNTS, CONTACTS);
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CALENDAR, CALENDAR);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CALENDAR, CALENDAR);
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.SEND_SMS, SMS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_SMS, SMS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_SMS, SMS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_MMS, SMS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_WAP_PUSH, SMS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CELL_BROADCASTS, SMS);
+
+ // If permissions are added to the Storage group, they must be added to the
+ // STORAGE_PERMISSIONS list in PermissionManagerService in frameworks/base
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_EXTERNAL_STORAGE, STORAGE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, STORAGE);
+// if (SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+// PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_MEDIA_LOCATION, STORAGE);
+// }
+
+// if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_AUDIO, READ_MEDIA_AURAL);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_IMAGES, READ_MEDIA_VISUAL);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_VIDEO, READ_MEDIA_VISUAL);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_MEDIA_LOCATION, READ_MEDIA_VISUAL);
+// }
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_BACKGROUND_LOCATION, LOCATION);
+
+// if (SDK_INT >= Build.VERSION_CODES.S) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_ADVERTISE, NEARBY_DEVICES);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_CONNECT, NEARBY_DEVICES);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_SCAN, NEARBY_DEVICES);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.UWB_RANGING, NEARBY_DEVICES);
+// }
+// if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.NEARBY_WIFI_DEVICES, NEARBY_DEVICES);
+// }
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CALL_LOG, CALL_LOG);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CALL_LOG, CALL_LOG);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.PROCESS_OUTGOING_CALLS, CALL_LOG);
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_PHONE_STATE, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.READ_PHONE_NUMBERS, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.CALL_PHONE, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ADD_VOICEMAIL, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.USE_SIP, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ANSWER_PHONE_CALLS, PHONE);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACCEPT_HANDOVER, PHONE);
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.RECORD_AUDIO, MICROPHONE);
+// if (SDK_INT >= Build.VERSION_CODES.S) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.RECORD_BACKGROUND_AUDIO, MICROPHONE);
+// }
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.ACTIVITY_RECOGNITION, ACTIVITY_RECOGNITION);
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.CAMERA, CAMERA);
+// if (SDK_INT >= Build.VERSION_CODES.S) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BACKGROUND_CAMERA, CAMERA);
+// }
+
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BODY_SENSORS, SENSORS);
+
+// if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ PLATFORM_PERMISSIONS.put(Manifest.permission.POST_NOTIFICATIONS, NOTIFICATIONS);
+ PLATFORM_PERMISSIONS.put(Manifest.permission.BODY_SENSORS_BACKGROUND, SENSORS);
+// }
+
+ PLATFORM_PERMISSION_GROUPS = new ArrayMap<>();
+ int numPlatformPermissions = PLATFORM_PERMISSIONS.size();
+ for (int i = 0; i < numPlatformPermissions; i++) {
+ String permission = PLATFORM_PERMISSIONS.keyAt(i);
+ String permissionGroup = PLATFORM_PERMISSIONS.valueAt(i);
+
+ ArrayList<String> permissionsOfThisGroup = PLATFORM_PERMISSION_GROUPS.get(
+ permissionGroup);
+ if (permissionsOfThisGroup == null) {
+ permissionsOfThisGroup = new ArrayList<>();
+ PLATFORM_PERMISSION_GROUPS.put(permissionGroup, permissionsOfThisGroup);
+ }
+
+ permissionsOfThisGroup.add(permission);
+ }
+
+ ONE_TIME_PERMISSION_GROUPS = new ArraySet<>();
+ ONE_TIME_PERMISSION_GROUPS.add(LOCATION);
+ ONE_TIME_PERMISSION_GROUPS.add(CAMERA);
+ ONE_TIME_PERMISSION_GROUPS.add(MICROPHONE);
+
+ PERM_SENSOR_CODES = new ArrayMap<>();
+// if (SDK_INT >= Build.VERSION_CODES.S) {
+ PERM_SENSOR_CODES.put(CAMERA, SensorPrivacyManager.Sensors.CAMERA);
+ PERM_SENSOR_CODES.put(MICROPHONE, SensorPrivacyManager.Sensors.MICROPHONE);
+// }
+
+ }
+
+ private Utils() {
+ /* do nothing - hide constructor */
+ }
+
+ private static ArrayMap<UserHandle, Context> sUserContexts = new ArrayMap<>();
+
+ /**
+ * Creates and caches a PackageContext for the requested user, or returns the previously cached
+ * value. The package of the PackageContext is the application's package.
+ *
+ * @param app The currently running application
+ * @param user The desired user for the context
+ *
+ * @return The generated or cached Context for the requested user
+ *
+ * @throws PackageManager.NameNotFoundException If the app has no package name attached
+ */
+ public static @NonNull Context getUserContext(Application app, UserHandle user) throws
+ PackageManager.NameNotFoundException {
+ if (!sUserContexts.containsKey(user)) {
+ sUserContexts.put(user, app.getApplicationContext()
+ .createPackageContextAsUser(app.getPackageName(), 0, user));
+ }
+ return sUserContexts.get(user);
+ }
+
+ /**
+ * Returns true if a permission is dangerous, installed, and not removed
+ * @param permissionInfo The permission we wish to check
+ * @return If all of the conditions are met
+ */
+ public static boolean isPermissionDangerousInstalledNotRemoved(PermissionInfo permissionInfo) {
+ return permissionInfo != null
+ && permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
+ && (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) != 0
+ && (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) == 0;
+ }
+
+ /**
+ * Get permission group a platform permission belongs to, or null if the permission is not a
+ * platform permission.
+ *
+ * @param permission the permission to resolve
+ *
+ * @return The group the permission belongs to
+ */
+ public static @Nullable String getGroupOfPlatformPermission(@NonNull String permission) {
+ return PLATFORM_PERMISSIONS.get(permission);
+ }
+
+ /**
+ * Get name of the permission group a permission belongs to.
+ *
+ * @param permission the {@link PermissionInfo info} of the permission to resolve
+ *
+ * @return The group the permission belongs to
+ */
+ public static @Nullable String getGroupOfPermission(@NonNull PermissionInfo permission) {
+ String groupName = Utils.getGroupOfPlatformPermission(permission.name);
+ if (groupName == null) {
+ groupName = permission.group;
+ }
+
+ return groupName;
+ }
+
+ /**
+ * Get the names for all platform permissions belonging to a group.
+ *
+ * @param group the group
+ *
+ * @return The permission names or an empty list if the
+ * group is not does not have platform runtime permissions
+ */
+ public static @NonNull List<String> getPlatformPermissionNamesOfGroup(@NonNull String group) {
+ final ArrayList<String> permissions = PLATFORM_PERMISSION_GROUPS.get(group);
+ return (permissions != null) ? permissions : Collections.emptyList();
+ }
+
+ /**
+ * Get the {@link PermissionInfo infos} for all platform permissions belonging to a group.
+ *
+ * @param pm Package manager to use to resolve permission infos
+ * @param group the group
+ *
+ * @return The infos for platform permissions belonging to the group or an empty list if the
+ * group is not does not have platform runtime permissions
+ */
+ public static @NonNull List<PermissionInfo> getPlatformPermissionsOfGroup(
+ @NonNull PackageManager pm, @NonNull String group) {
+ ArrayList<PermissionInfo> permInfos = new ArrayList<>();
+
+ ArrayList<String> permissions = PLATFORM_PERMISSION_GROUPS.get(group);
+ if (permissions == null) {
+ return Collections.emptyList();
+ }
+
+ int numPermissions = permissions.size();
+ for (int i = 0; i < numPermissions; i++) {
+ String permName = permissions.get(i);
+ PermissionInfo permInfo;
+ try {
+ permInfo = pm.getPermissionInfo(permName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException(permName + " not defined by platform", e);
+ }
+
+ permInfos.add(permInfo);
+ }
+
+ return permInfos;
+ }
+
+ /**
+ * Get the {@link PermissionInfo infos} for all permission infos belonging to a group.
+ *
+ * @param pm Package manager to use to resolve permission infos
+ * @param group the group
+ *
+ * @return The infos of permissions belonging to the group or an empty list if the group
+ * does not have runtime permissions
+ */
+ public static @NonNull List<PermissionInfo> getPermissionInfosForGroup(
+ @NonNull PackageManager pm, @NonNull String group)
+ throws PackageManager.NameNotFoundException {
+ List<PermissionInfo> permissions = pm.queryPermissionsByGroup(group, 0);
+ permissions.addAll(getPlatformPermissionsOfGroup(pm, group));
+
+ /*
+ * If the undefined group is requested, the package manager will return all platform
+ * permissions, since they are marked as Undefined in the manifest. Do not return these
+ * permissions.
+ */
+ if (group.equals(Manifest.permission_group.UNDEFINED)) {
+ List<PermissionInfo> undefinedPerms = new ArrayList<>();
+ for (PermissionInfo permissionInfo : permissions) {
+ String permGroup = getGroupOfPlatformPermission(permissionInfo.name);
+ if (permGroup == null || permGroup.equals(Manifest.permission_group.UNDEFINED)) {
+ undefinedPerms.add(permissionInfo);
+ }
+ }
+ return undefinedPerms;
+ }
+
+ return permissions;
+ }
+
+ /**
+ * Get the {@link PermissionInfo infos} for all runtime installed permission infos belonging to
+ * a group.
+ *
+ * @param pm Package manager to use to resolve permission infos
+ * @param group the group
+ *
+ * @return The infos of installed runtime permissions belonging to the group or an empty list
+ * if the group does not have runtime permissions
+ */
+ public static @NonNull List<PermissionInfo> getInstalledRuntimePermissionInfosForGroup(
+ @NonNull PackageManager pm, @NonNull String group)
+ throws PackageManager.NameNotFoundException {
+ List<PermissionInfo> permissions = pm.queryPermissionsByGroup(group, 0);
+ permissions.addAll(getPlatformPermissionsOfGroup(pm, group));
+
+ List<PermissionInfo> installedRuntime = new ArrayList<>();
+ for (PermissionInfo permissionInfo: permissions) {
+ if (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
+ && (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) != 0
+ && (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) == 0) {
+ installedRuntime.add(permissionInfo);
+ }
+ }
+
+ /*
+ * If the undefined group is requested, the package manager will return all platform
+ * permissions, since they are marked as Undefined in the manifest. Do not return these
+ * permissions.
+ */
+ if (group.equals(Manifest.permission_group.UNDEFINED)) {
+ List<PermissionInfo> undefinedPerms = new ArrayList<>();
+ for (PermissionInfo permissionInfo : installedRuntime) {
+ String permGroup = getGroupOfPlatformPermission(permissionInfo.name);
+ if (permGroup == null || permGroup.equals(Manifest.permission_group.UNDEFINED)) {
+ undefinedPerms.add(permissionInfo);
+ }
+ }
+ return undefinedPerms;
+ }
+
+ return installedRuntime;
+ }
+
+ /**
+ * Get the {@link PackageItemInfo infos} for the given permission group.
+ *
+ * @param groupName the group
+ * @param context the {@code Context} to retrieve {@code PackageManager}
+ *
+ * @return The info of permission group or null if the group does not have runtime permissions.
+ */
+ public static @Nullable PackageItemInfo getGroupInfo(@NonNull String groupName,
+ @NonNull Context context) {
+ try {
+ return context.getPackageManager().getPermissionGroupInfo(groupName, 0);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ try {
+ return context.getPackageManager().getPermissionInfo(groupName, 0);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ return null;
+ }
+
+ /**
+ * Get the {@link PermissionInfo infos} for all permission infos belonging to a group.
+ *
+ * @param groupName the group
+ * @param context the {@code Context} to retrieve {@code PackageManager}
+ *
+ * @return The infos of permissions belonging to the group or null if the group does not have
+ * runtime permissions.
+ */
+ public static @Nullable List<PermissionInfo> getGroupPermissionInfos(@NonNull String groupName,
+ @NonNull Context context) {
+ try {
+ return Utils.getPermissionInfosForGroup(context.getPackageManager(), groupName);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ try {
+ PermissionInfo permissionInfo = context.getPackageManager()
+ .getPermissionInfo(groupName, 0);
+ List<PermissionInfo> permissions = new ArrayList<>();
+ permissions.add(permissionInfo);
+ return permissions;
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ return null;
+ }
+
+ /**
+ * Get the names of the platform permission groups.
+ *
+ * @return the names of the platform permission groups.
+ */
+ public static List<String> getPlatformPermissionGroups() {
+ return new ArrayList<>(PLATFORM_PERMISSION_GROUPS.keySet());
+ }
+
+ /**
+ * Get the names of the runtime platform permissions
+ *
+ * @return the names of the runtime platform permissions.
+ */
+ public static List<String> getRuntimePlatformPermissionNames() {
+ return new ArrayList<>(PLATFORM_PERMISSIONS.keySet());
+ }
+
+ /**
+ * Is the permissions a platform runtime permission
+ *
+ * @return the names of the runtime platform permissions.
+ */
+ public static boolean isRuntimePlatformPermission(@NonNull String permission) {
+ return PLATFORM_PERMISSIONS.containsKey(permission);
+ }
+
+ /**
+ * Is the group or background group user sensitive?
+ *
+ * @param group The group that might be user sensitive
+ *
+ * @return {@code true} if the group (or it's subgroup) is user sensitive.
+ */
+ public static boolean isGroupOrBgGroupUserSensitive(AppPermissionGroup group) {
+ return group.isUserSensitive() || (group.getBackgroundPermissions() != null
+ && group.getBackgroundPermissions().isUserSensitive());
+ }
+
+ /**
+ * Whether or not the given package has non-isolated storage permissions
+ * @param context The current context
+ * @param packageName The package name to check
+ * @return True if the package has access to non-isolated storage, false otherwise
+ * @throws NameNotFoundException
+ */
+ public static boolean isNonIsolatedStorage(@NonNull Context context,
+ @NonNull String packageName) throws NameNotFoundException {
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
+ AppOpsManager manager = context.getSystemService(AppOpsManager.class);
+
+
+ return packageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.P
+ || (packageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R
+ && manager.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE,
+ packageInfo.applicationInfo.uid, packageInfo.packageName) == MODE_ALLOWED);
+ }
+
+ /**
+ * Build a string representing the given time if it happened on the current day and the date
+ * otherwise.
+ *
+ * @param context the context.
+ * @param lastAccessTime the time in milliseconds.
+ *
+ * @return a string representing the time or date of the given time or null if the time is 0.
+ */
+ public static @Nullable String getAbsoluteTimeString(@NonNull Context context,
+ long lastAccessTime) {
+ if (lastAccessTime == 0) {
+ return null;
+ }
+ if (isToday(lastAccessTime)) {
+ return DateFormat.getTimeFormat(context).format(lastAccessTime);
+ } else {
+ return DateFormat.getMediumDateFormat(context).format(lastAccessTime);
+ }
+ }
+
+ /**
+ * Check whether the given time (in milliseconds) is in the current day.
+ *
+ * @param time the time in milliseconds
+ *
+ * @return whether the given time is in the current day.
+ */
+ private static boolean isToday(long time) {
+ Calendar today = Calendar.getInstance(Locale.getDefault());
+ today.setTimeInMillis(System.currentTimeMillis());
+ today.set(Calendar.HOUR_OF_DAY, 0);
+ today.set(Calendar.MINUTE, 0);
+ today.set(Calendar.SECOND, 0);
+ today.set(Calendar.MILLISECOND, 0);
+
+ Calendar date = Calendar.getInstance(Locale.getDefault());
+ date.setTimeInMillis(time);
+ return !date.before(today);
+ }
+
+ /**
+ * Whether the Location Access Check is enabled.
+ *
+ * @return {@code true} iff the Location Access Check is enabled.
+ */
+ public static boolean isLocationAccessCheckEnabled() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_CHECK_ENABLED, true);
+ }
+
+ /**
+ * Get one time permissions timeout
+ */
+ public static long getOneTimePermissionsTimeout() {
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
+ PROPERTY_ONE_TIME_PERMISSIONS_TIMEOUT_MILLIS, ONE_TIME_PERMISSIONS_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * Returns the delay in milliseconds before revoking permissions at the end of a one-time
+ * permission session if all processes have been killed.
+ * If the session was triggered by a self-revocation, then revocation should happen
+ * immediately. For a regular one-time permission session, a grace period allows a quick
+ * app restart without losing the permission.
+ * @param isSelfRevoked If true, return the delay for a self-revocation session. Otherwise,
+ * return delay for a regular one-time permission session.
+ */
+ public static long getOneTimePermissionsKilledDelay(boolean isSelfRevoked) {
+ if (isSelfRevoked) {
+ // For a self-revoked session, we revoke immediately when the process dies.
+ return 0;
+ }
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
+ PROPERTY_ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS,
+ ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS);
+ }
+
+ /**
+ * Whether the permission group supports one-time
+ * @param permissionGroup The permission group to check
+ * @return {@code true} iff the group supports one-time
+ */
+ public static boolean supportsOneTimeGrant(String permissionGroup) {
+ return ONE_TIME_PERMISSION_GROUPS.contains(permissionGroup);
+ }
+
+ /**
+ * Checks whether a package has an active one-time permission according to the system server's
+ * flags
+ *
+ * @param context the {@code Context} to retrieve {@code PackageManager}
+ * @param packageName The package to check for
+ * @return Whether a package has an active one-time permission
+ */
+ public static boolean hasOneTimePermissions(Context context, String packageName) {
+ String[] permissions;
+ PackageManager pm = context.getPackageManager();
+ try {
+ permissions = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
+ .requestedPermissions;
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "Checking for one-time permissions in nonexistent package");
+ return false;
+ }
+ if (permissions == null) {
+ return false;
+ }
+ for (String permissionName : permissions) {
+ if ((pm.getPermissionFlags(permissionName, packageName, Process.myUserHandle())
+ & PackageManager.FLAG_PERMISSION_ONE_TIME) != 0
+ && pm.checkPermission(permissionName, packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the label of the Settings application
+ *
+ * @param pm The packageManager used to get the activity resolution
+ *
+ * @return The CharSequence title of the settings app
+ */
+ @Nullable
+ public static CharSequence getSettingsLabelForNotifications(PackageManager pm) {
+ // We pretend we're the Settings app sending the notification, so figure out its name.
+ Intent openSettingsIntent = new Intent(Settings.ACTION_SETTINGS);
+ ResolveInfo resolveInfo = pm.resolveActivity(openSettingsIntent, MATCH_SYSTEM_ONLY);
+ if (resolveInfo == null) {
+ return null;
+ }
+ return pm.getApplicationLabel(resolveInfo.activityInfo.applicationInfo);
+ }
+
+ /**
+ * Get all the exempted packages.
+ */
+ public static Set<String> getExemptedPackages(@NonNull RoleManager roleManager) {
+ Set<String> exemptedPackages = new HashSet<>();
+
+ exemptedPackages.add(SYSTEM_PKG);
+ for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
+ exemptedPackages.addAll(roleManager.getRoleHolders(EXEMPTED_ROLES[i]));
+ }
+
+ return exemptedPackages;
+ }
+
+ /**
+ * Returns if the permission group is Camera or Microphone (status bar indicators).
+ **/
+ public static boolean isStatusBarIndicatorPermission(@NonNull String permissionGroupName) {
+ return CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName);
+ }
+
+ /**
+ * Navigate to notification settings for all apps
+ * @param context The current Context
+ */
+ public static void navigateToNotificationSettings(@NonNull Context context) {
+ Intent notificationIntent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
+ context.startActivity(notificationIntent);
+ }
+
+ /**
+ * Navigate to notification settings for an app
+ * @param context The current Context
+ * @param packageName The package to navigate to
+ * @param user Specifies the user of the package which should be navigated to. If null, the
+ * current user is used.
+ */
+ public static void navigateToAppNotificationSettings(@NonNull Context context,
+ @NonNull String packageName, @NonNull UserHandle user) {
+ Intent notificationIntent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+ notificationIntent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+ context.startActivityAsUser(notificationIntent, user);
+ }
+
+ /**
+ * Returns if a card should be shown if the sensor is blocked
+ **/
+ public static boolean shouldDisplayCardIfBlocked(@NonNull String permissionGroupName) {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_WARNING_BANNER_DISPLAY_ENABLED, true) && (
+ CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName)
+ || LOCATION.equals(permissionGroupName));
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 0e4870af9930..9a8f1a55f1cf 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -315,7 +315,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
out.append("\n");
for (int associationId : mConnectedBtDevices) {
AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
+ out.append(" ").append(a.toString()).append('\n');
}
}
@@ -326,7 +326,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
out.append("\n");
for (int associationId : mNearbyBleDevices) {
AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
+ out.append(" ").append(a.toString()).append('\n');
}
}
@@ -337,7 +337,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
out.append("\n");
for (int associationId : mReportedSelfManagedDevices) {
AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
+ out.append(" ").append(a.toString()).append('\n');
}
}
}
diff --git a/services/companion/java/com/android/server/companion/proto/companion_apps_permissions.proto b/services/companion/java/com/android/server/companion/proto/companion_apps_permissions.proto
deleted file mode 100644
index b786bcc5e0df..000000000000
--- a/services/companion/java/com/android/server/companion/proto/companion_apps_permissions.proto
+++ /dev/null
@@ -1,37 +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.
- */
-
-syntax = "proto3";
-
-option java_multiple_files = true;
-
-/* Represents granted permissions of a list of apps */
-message CompanionAppsPermissions {
- // granted permissions of apps
- repeated AppPermissions appPermissions = 1;
-
- /* Represents the granted permissions of an app */
- message AppPermissions {
- // package name of the app
- string packageName = 1;
-
- // signing certificates used to sign the APK contents of this app
- bytes certificates = 2;
-
- // granted permissions
- repeated string permission = 3;
- }
-}
diff --git a/services/companion/java/com/android/server/companion/proto/companion_message.proto b/services/companion/java/com/android/server/companion/proto/companion_message.proto
index 2309be3afd94..893a0dbfc852 100644
--- a/services/companion/java/com/android/server/companion/proto/companion_message.proto
+++ b/services/companion/java/com/android/server/companion/proto/companion_message.proto
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -18,19 +18,33 @@ syntax = "proto3";
option java_multiple_files = true;
+package com.android.server.companion.proto;
+
/* Represents a message between companion devices */
message CompanionMessage {
- // id of the message
- int32 messageId = 1;
+ int32 id = 1;
+
+ PaginationInfo paginationInfo = 2;
+
+ Type type = 3;
- // type of the message
- CompanionMessageType type = 2;
+ // message body data
+ bytes data = 4;
- // data contained in the message
- bytes data = 3;
+ /* Message pagination info */
+ message PaginationInfo {
+ // id of the parent message, which should be the same for all the paginated messages
+ int32 parentId = 1;
+
+ // page number of the current message in [1, total]
+ int32 page = 2;
+
+ // total number of messages
+ int32 total = 3;
+ }
- // types of CompanionMessage
- enum CompanionMessageType {
+ /* Message type */
+ enum Type {
// default value for proto3
UNKNOWN = 0;
diff --git a/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java b/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java
new file mode 100644
index 000000000000..16a74ecd2068
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 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.companion.securechannel;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.companion.AssociationInfo;
+import android.util.Base64;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.companion.AssociationStore;
+import com.android.server.companion.CompanionApplicationController;
+
+/** Secure Comms Manager */
+@SuppressLint("LongLogTag")
+public class CompanionSecureCommunicationsManager {
+ static final String TAG = "CompanionDevice_SecureComms";
+ static final boolean DEBUG = false;
+
+ /** Listener for incoming decrypted messages. */
+ public interface Listener {
+ /** When an incoming message is decrypted. */
+ void onDecryptedMessageReceived(int messageId, int associationId, byte[] message);
+ }
+
+ private final AssociationStore mAssociationStore;
+ private final CompanionApplicationController mCompanionAppController;
+
+ @Nullable
+ private Listener mListener;
+
+ /** Constructor */
+ public CompanionSecureCommunicationsManager(AssociationStore associationStore,
+ CompanionApplicationController companionApplicationController) {
+ mAssociationStore = associationStore;
+ mCompanionAppController = companionApplicationController;
+ }
+
+ public void setListener(@NonNull Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Send a data to the associated companion device via secure channel (establishing one if
+ * needed).
+ * @param associationId associationId of the "recipient" companion device.
+ * @param messageId id of the message
+ * @param message data to be sent securely.
+ */
+ public void sendSecureMessage(int associationId, int messageId, @NonNull byte[] message) {
+ if (DEBUG) {
+ Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n"
+ + " message (Base64)=\"" + Base64.encodeToString(message, 0) + "\"");
+ }
+
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ if (association == null) {
+ throw new IllegalArgumentException(
+ "Association with ID " + associationId + " does not exist");
+ }
+ if (DEBUG) Log.d(TAG, " association=" + association);
+
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+
+ // Bind to the app if it hasn't been bound.
+ if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
+ Slog.d(TAG, "userId [" + userId + "] packageName [" + packageName
+ + "] is not bound. Binding it now to send a secure message.");
+ mCompanionAppController.bindCompanionApplication(userId, packageName,
+ association.isSelfManaged());
+
+ // TODO(b/202926196): implement: encrypt and pass on the companion application for
+ // transporting
+ mCompanionAppController.dispatchMessage(userId, packageName, associationId, messageId,
+ message);
+
+ Slog.d(TAG, "Unbinding userId [" + userId + "] packageName [" + packageName
+ + "]");
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
+ }
+
+ // TODO(b/202926196): implement: encrypt and pass on the companion application for
+ // transporting
+ mCompanionAppController.dispatchMessage(userId, packageName, associationId, messageId,
+ message);
+ }
+
+ /**
+ * Decrypt and dispatch message received from an associated companion device.
+ * @param associationId associationId of the "sender" companion device.
+ * @param encryptedMessage data.
+ */
+ public void receiveSecureMessage(int messageId, int associationId,
+ @NonNull byte[] encryptedMessage) {
+ if (DEBUG) {
+ Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n"
+ + " message (Base64)=\"" + Base64.encodeToString(encryptedMessage, 0) + "\"");
+ }
+
+ // TODO(b/202926196): implement: decrypt and dispatch
+
+ mListener.onDecryptedMessageReceived(messageId, associationId, encryptedMessage);
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/securechannel/OWNERS b/services/companion/java/com/android/server/companion/securechannel/OWNERS
new file mode 100644
index 000000000000..ecb97f402136
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/securechannel/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+
+sergeynv@google.com
+ewol@google.com
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index dc7573e20438..05e85e367be8 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -510,7 +510,7 @@ class InputController {
}
/** A helper class used to wait for an input device to be registered. */
- private class WaitForDevice implements AutoCloseable {
+ private class WaitForDevice implements AutoCloseable {
private final CountDownLatch mDeviceAddedLatch = new CountDownLatch(1);
private final InputManager.InputDeviceListener mListener;
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index ff1a495edcbb..4018be1670ad 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -228,7 +228,7 @@ public final class ContentCaptureManagerService extends
@Override // from SystemService
public boolean isUserSupported(TargetUser user) {
- return user.isFull() || user.isManagedProfile();
+ return user.isFull() || user.isProfile();
}
@Override // from SystemService
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 89c8ca567dd9..3dcf73d1fb17 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -130,6 +130,7 @@ java_library_static {
"android.hardware.vibrator-V2-java",
"app-compat-annotations",
"framework-tethering.stubs.module_lib",
+ "service-art.stubs.system_server",
"service-permission.stubs.system_server",
"service-sdksandbox.stubs.system_server",
],
diff --git a/services/core/OWNERS b/services/core/OWNERS
deleted file mode 100644
index 88d0b61a2ab6..000000000000
--- a/services/core/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index ed6110086089..7cb7c0bed0ea 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -28,6 +28,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageManager.SignatureResult;
import android.content.pm.SigningDetails.CertCapabilities;
import android.content.pm.overlay.OverlayPaths;
import android.os.Bundle;
@@ -503,9 +504,9 @@ public abstract class PackageManagerInternal {
/**
* Prunes the cache of the APKs in the given APEXes.
- * @param apexPackages The list of APEX packages that may contain APK-in-APEX.
+ * @param apexPackageNames The list of APEX package names that may contain APK-in-APEX.
*/
- public abstract void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages);
+ public abstract void pruneCachedApksInApex(@NonNull List<String> apexPackageNames);
/**
* @return The SetupWizard package name.
@@ -556,18 +557,23 @@ public abstract class PackageManagerInternal {
/**
* Set which overlay to use for a package.
* @param userId The user for which to update the overlays.
- * @param targetPackageName The package name of the package for which to update the overlays.
- * @param overlayPaths The complete list of overlay paths that should be enabled for
+ * @param pendingChanges is a map to describe all overlay targets and their related overlay
+ * paths. Its key is the overlay target package and its value is the
+ * complete list of overlay paths that should be enabled for
* the target. Previously enabled overlays not specified in the list
* will be disabled. Pass in null or empty paths to disable all overlays.
* The order of the items is significant if several overlays modify the
- * same resource.
+ * same resource. To pass the concrete ArrayMap type is to reduce the
+ * overheads of system server.
* @param outUpdatedPackageNames An output list that contains the package names of packages
* affected by the update of enabled overlays.
- * @return true if all packages names were known by the package manager, false otherwise
+ * @param outInvalidPackageNames An output list that contains the package names of packages
+ * are not valid.
*/
- public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
- @Nullable OverlayPaths overlayPaths, Set<String> outUpdatedPackageNames);
+ public abstract void setEnabledOverlayPackages(int userId,
+ @NonNull ArrayMap<String, OverlayPaths> pendingChanges,
+ @NonNull Set<String> outUpdatedPackageNames,
+ @NonNull Set<String> outInvalidPackageNames);
/**
* Resolves an activity intent, allowing instant apps to be resolved.
@@ -845,13 +851,6 @@ public abstract class PackageManagerInternal {
public abstract int[] getPermissionGids(String permissionName, int userId);
/**
- * Return if device is currently in a "core" boot environment, typically
- * used to support full-disk encryption. Only apps marked with
- * {@code coreApp} attribute are available.
- */
- public abstract boolean isOnlyCoreApps();
-
- /**
* Make a best-effort attempt to provide the requested free disk space by
* deleting cached files.
*
@@ -1285,4 +1284,15 @@ public abstract class PackageManagerInternal {
public abstract void shutdown();
public abstract DynamicCodeLogger getDynamicCodeLogger();
+
+ /**
+ * Compare the signatures of two packages that are installed in different users.
+ *
+ * @param uid1 First UID whose signature will be compared.
+ * @param uid2 Second UID whose signature will be compared.
+ * @return {@link PackageManager#SIGNATURE_MATCH} if signatures are matched.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ */
+ public abstract @SignatureResult int checkUidSignaturesForAllUsers(int uid1, int uid2);
}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 7f2d54239366..b8815454cadb 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -21,15 +21,12 @@ import static android.system.OsConstants.O_RDONLY;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.MessageQueue.OnFileDescriptorEventListener;
import android.os.RecoverySystem;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Downloads;
import android.system.ErrnoException;
@@ -99,11 +96,13 @@ public class BootReceiver extends BroadcastReceiver {
// example: fs_stat,/dev/block/platform/soc/by-name/userdata,0x5
private static final String FS_STAT_PATTERN = "fs_stat,[^,]*/([^/,]+),(0x[0-9a-fA-F]+)";
- private static final int FS_STAT_FS_FIXED = 0x400; // should match with fs_mgr.cpp:FsStatFlags
+ private static final int FS_STAT_FSCK_FS_FIXED =
+ 0x400; // should match with fs_mgr.cpp:FsStatFlags
private static final String FSCK_PASS_PATTERN = "Pass ([1-9]E?):";
private static final String FSCK_TREE_OPTIMIZATION_PATTERN =
"Inode [0-9]+ extent tree.*could be shorter";
- private static final String FSCK_FS_MODIFIED = "FILE SYSTEM WAS MODIFIED";
+ private static final String E2FSCK_FS_MODIFIED = "FILE SYSTEM WAS MODIFIED";
+ private static final String F2FS_FSCK_FS_MODIFIED = "[FSCK] Unreachable";
// ro.boottime.init.mount_all. + postfix for mount_all duration
private static final String[] MOUNT_DURATION_PROPS_POSTFIX =
new String[] { "early", "default", "late" };
@@ -141,15 +140,7 @@ public class BootReceiver extends BroadcastReceiver {
Slog.e(TAG, "Can't log boot events", e);
}
try {
- boolean onlyCore = false;
- try {
- onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
- "package")).isOnlyCoreApps();
- } catch (RemoteException e) {
- }
- if (!onlyCore) {
- removeOldUpdatePackages(context);
- }
+ removeOldUpdatePackages(context);
} catch (Exception e) {
Slog.e(TAG, "Can't remove old update packages", e);
}
@@ -475,9 +466,9 @@ public class BootReceiver extends BroadcastReceiver {
int lineNumber = 0;
int lastFsStatLineNumber = 0;
for (String line : lines) { // should check all lines
- if (line.contains(FSCK_FS_MODIFIED)) {
+ if (line.contains(E2FSCK_FS_MODIFIED) || line.contains(F2FS_FSCK_FS_MODIFIED)) {
uploadNeeded = true;
- } else if (line.contains("fs_stat")){
+ } else if (line.contains("fs_stat")) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
handleFsckFsStat(matcher, lines, lastFsStatLineNumber, lineNumber);
@@ -489,12 +480,13 @@ public class BootReceiver extends BroadcastReceiver {
lineNumber++;
}
- if (uploadEnabled && uploadNeeded ) {
+ if (uploadEnabled && uploadNeeded) {
addFileToDropBox(db, timestamps, headers, "/dev/fscklogs/log", maxSize, tag);
}
- // Remove the file so we don't re-upload if the runtime restarts.
- file.delete();
+ // Rename the file so we don't re-upload if the runtime restarts.
+ File pfile = new File("/dev/fscklogs/fsck");
+ file.renameTo(pfile);
}
private static void logFsMountTime() {
@@ -688,7 +680,7 @@ public class BootReceiver extends BroadcastReceiver {
public static int fixFsckFsStat(String partition, int statOrg, String[] lines,
int startLineNumber, int endLineNumber) {
int stat = statOrg;
- if ((stat & FS_STAT_FS_FIXED) != 0) {
+ if ((stat & FS_STAT_FSCK_FS_FIXED) != 0) {
// fs was fixed. should check if quota warning was caused by tree optimization.
// This is not a real fix but optimization, so should not be counted as a fs fix.
Pattern passPattern = Pattern.compile(FSCK_PASS_PATTERN);
@@ -701,7 +693,8 @@ public class BootReceiver extends BroadcastReceiver {
String otherFixLine = null;
for (int i = startLineNumber; i < endLineNumber; i++) {
String line = lines[i];
- if (line.contains(FSCK_FS_MODIFIED)) { // no need to parse above this
+ if (line.contains(E2FSCK_FS_MODIFIED)
+ || line.contains(F2FS_FSCK_FS_MODIFIED)) { // no need to parse above this
break;
} else if (line.startsWith("Pass ")) {
Matcher matcher = passPattern.matcher(line);
@@ -729,9 +722,9 @@ public class BootReceiver extends BroadcastReceiver {
}
} else if (line.startsWith("Update quota info") && currentPass.equals("5")) {
// follows "[QUOTA WARNING]", ignore
- } else if (line.startsWith("Timestamp(s) on inode") &&
- line.contains("beyond 2310-04-04 are likely pre-1970") &&
- currentPass.equals("1")) {
+ } else if (line.startsWith("Timestamp(s) on inode")
+ && line.contains("beyond 2310-04-04 are likely pre-1970")
+ && currentPass.equals("1")) {
Slog.i(TAG, "fs_stat, partition:" + partition + " found timestamp adjustment:"
+ line);
// followed by next line, "Fix? yes"
@@ -759,7 +752,7 @@ public class BootReceiver extends BroadcastReceiver {
} else if ((foundTreeOptimization && foundQuotaFix) || foundTimestampAdjustment) {
// not a real fix, so clear it.
Slog.i(TAG, "fs_stat, partition:" + partition + " fix ignored");
- stat &= ~FS_STAT_FS_FIXED;
+ stat &= ~FS_STAT_FSCK_FS_FIXED;
}
}
return stat;
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index c4e84a4cd138..a9bdf063e8a6 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -16,6 +16,10 @@
package com.android.server;
+import static android.Manifest.permission.TRANSMIT_IR;
+
+import android.annotation.EnforcePermission;
+import android.annotation.RequiresNoPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.IConsumerIrService;
@@ -60,6 +64,7 @@ public class ConsumerIrService extends IConsumerIrService.Stub {
}
@Override
+ @RequiresNoPermission
public boolean hasIrEmitter() {
return mHasNativeHal;
}
@@ -85,12 +90,8 @@ public class ConsumerIrService extends IConsumerIrService.Stub {
@Override
+ @EnforcePermission(TRANSMIT_IR)
public void transmit(String packageName, int carrierFrequency, int[] pattern) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires TRANSMIT_IR permission");
- }
-
long totalXmitTime = 0;
for (int slice : pattern) {
@@ -125,12 +126,8 @@ public class ConsumerIrService extends IConsumerIrService.Stub {
}
@Override
+ @EnforcePermission(TRANSMIT_IR)
public int[] getCarrierFrequencies() {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires TRANSMIT_IR permission");
- }
-
throwIfNoIrEmitter();
synchronized(mHalLock) {
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 99e12a8f9f55..ce0e69c40f67 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -91,6 +91,10 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
if (!volume.isMountedWritable()) {
continue;
}
+ // gsid only supports vfat external storage.
+ if (!"vfat".equalsIgnoreCase(volume.fsType)) {
+ continue;
+ }
DiskInfo disk = volume.getDisk();
long mega = disk.size >> 20;
Slog.i(TAG, volume.getPath() + ": " + mega + " MB");
diff --git a/services/core/java/com/android/server/LocalManagerRegistry.java b/services/core/java/com/android/server/LocalManagerRegistry.java
index 85795fff61ee..7310f929d0ee 100644
--- a/services/core/java/com/android/server/LocalManagerRegistry.java
+++ b/services/core/java/com/android/server/LocalManagerRegistry.java
@@ -54,6 +54,21 @@ public final class LocalManagerRegistry {
}
/**
+ * Returns a manager from the registry, or throws {@link ManagerNotFoundException} if not found.
+ *
+ * @hide
+ */
+ @NonNull
+ public static <T> T getManagerOrThrow(@NonNull Class<T> managerClass)
+ throws ManagerNotFoundException {
+ T manager = getManager(managerClass);
+ if (manager == null) {
+ throw new ManagerNotFoundException(managerClass);
+ }
+ return manager;
+ }
+
+ /**
* Adds a manager to the registry.
*
* @param managerClass the class that the manager implements
@@ -70,4 +85,15 @@ public final class LocalManagerRegistry {
sManagers.put(managerClass, manager);
}
}
+
+ /**
+ * Exception thrown when no local manager published for given class.
+ *
+ * @hide
+ */
+ public static class ManagerNotFoundException extends Exception {
+ public <T> ManagerNotFoundException(@NonNull Class<T> managerClass) {
+ super("Local manager " + managerClass.getName() + " does not exist or is not ready");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/MemoryPressureUtil.java b/services/core/java/com/android/server/MemoryPressureUtil.java
deleted file mode 100644
index c34dc2f5a9b1..000000000000
--- a/services/core/java/com/android/server/MemoryPressureUtil.java
+++ /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.server;
-
-import android.os.StrictMode;
-import android.util.Slog;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-
-/**
- * Utility method for memory pressure (PSI).
- */
-public final class MemoryPressureUtil {
- private static final String FILE = "/proc/pressure/memory";
- private static final String TAG = "MemoryPressure";
-
- /**
- * @return a stanza about memory PSI to add to a report.
- */
- public static String currentPsiState() {
- final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
- StringWriter contents = new StringWriter();
- try {
- if (new File(FILE).exists()) {
- contents.append("----- Output from /proc/pressure/memory -----\n");
- contents.append(IoUtils.readFileAsString(FILE));
- contents.append("----- End output from /proc/pressure/memory -----\n\n");
- }
- } catch (IOException e) {
- Slog.e(TAG, "Could not read " + FILE, e);
- } finally {
- StrictMode.setThreadPolicy(savedPolicy);
- }
- return contents.toString();
- }
-
- private MemoryPressureUtil(){}
-}
diff --git a/services/core/java/com/android/server/ResourcePressureUtil.java b/services/core/java/com/android/server/ResourcePressureUtil.java
new file mode 100644
index 000000000000..1a439e14f30d
--- /dev/null
+++ b/services/core/java/com/android/server/ResourcePressureUtil.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.os.StrictMode;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Utility method for resource pressure (PSI).
+ */
+public final class ResourcePressureUtil {
+
+ private static final String PSI_ROOT = "/proc/pressure";
+ private static final String TAG = "ResourcePressureUtil";
+ private static final List<String> PSI_FILES = Arrays.asList(
+ PSI_ROOT + "/memory",
+ PSI_ROOT + "/cpu",
+ PSI_ROOT + "/io"
+ );
+
+ private static String readResourcePsiState(String filePath) {
+ StringWriter contents = new StringWriter();
+ try {
+ if (new File(filePath).exists()) {
+ contents.append("----- Output from " + filePath + " -----\n");
+ contents.append(IoUtils.readFileAsString(filePath));
+ contents.append("----- End output from " + filePath + " -----\n");
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, " could not read " + filePath, e);
+ }
+ return contents.toString();
+ }
+
+ /**
+ * @return a stanza about PSI to add to a report.
+ */
+ public static String currentPsiState() {
+ final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+ StringWriter aggregatedState = new StringWriter();
+
+ try {
+ PSI_FILES.stream()
+ .map(ResourcePressureUtil::readResourcePsiState)
+ .forEach(aggregatedState::append);
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
+ }
+
+ String psiState = aggregatedState.toString();
+
+ return psiState.length() > 0 ? psiState + "\n" : psiState;
+ }
+
+ private ResourcePressureUtil(){}
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5eec6e58e925..77b582e96899 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1557,10 +1557,6 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mLock")
private void onVolumeCreatedLocked(VolumeInfo vol) {
- if (mPmInternal.isOnlyCoreApps()) {
- Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
- return;
- }
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
@@ -3732,7 +3728,8 @@ class StorageManagerService extends IStorageManager.Stub
try {
final PackageManager.Property noAppStorageProp = mContext.getPackageManager()
- .getProperty(PackageManager.PROPERTY_NO_APP_DATA_STORAGE, callingPkg);
+ .getPropertyAsUser(PackageManager.PROPERTY_NO_APP_DATA_STORAGE, callingPkg,
+ null /* className */, userId);
if (noAppStorageProp != null && noAppStorageProp.getBoolean()) {
throw new SecurityException(callingPkg + " should not have " + appPath);
}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 206a3109e6a8..933d2596aed8 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -146,14 +146,16 @@ public abstract class SystemService {
// moment it's started until after it's shutdown).
private final @UserIdInt int mUserId;
private final boolean mFull;
- private final boolean mManagedProfile;
+ private final boolean mProfile;
+ private final String mUserType;
private final boolean mPreCreated;
/** @hide */
public TargetUser(@NonNull UserInfo userInfo) {
mUserId = userInfo.id;
mFull = userInfo.isFull();
- mManagedProfile = userInfo.isManagedProfile();
+ mProfile = userInfo.isProfile();
+ mUserType = userInfo.userType;
mPreCreated = userInfo.preCreated;
}
@@ -167,12 +169,24 @@ public abstract class SystemService {
}
/**
- * Checks if the target user is a managed profile.
+ * Checks if the target user is a {@link UserInfo#isProfile() profile]}.
+ *
+ * @hide
+ */
+ public boolean isProfile() {
+ return mProfile;
+ }
+
+ /**
+ * Checks if the target user is a {@link UserInfo#isManagedProfile() managed profile]}.
+ *
+ * This is only specifically for managed profiles; for profiles more generally,
+ * use {@link #isProfile()}.
*
* @hide
*/
public boolean isManagedProfile() {
- return mManagedProfile;
+ return UserManager.isUserTypeManagedProfile(mUserType);
}
/**
@@ -212,16 +226,16 @@ public abstract class SystemService {
public void dump(@NonNull PrintWriter pw) {
pw.print(getUserIdentifier());
- if (!isFull() && !isManagedProfile()) return;
+ if (!isFull() && !isProfile()) return;
pw.print('(');
boolean addComma = false;
if (isFull()) {
pw.print("full");
}
- if (isManagedProfile()) {
+ if (isProfile()) {
if (addComma) pw.print(',');
- pw.print("mp");
+ pw.print("profile");
}
pw.print(')');
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 78df983c83f7..9455a89232cf 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -23,6 +23,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.SystemClock;
@@ -82,8 +83,6 @@ public final class SystemServiceManager implements Dumpable {
private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser
private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onCompletedEventUser
- // Whether to use multiple threads to run user lifecycle phases in parallel.
- private static boolean sUseLifecycleThreadPool = true;
// The default number of threads to use if lifecycle thread pool is enabled.
private static final int DEFAULT_MAX_USER_POOL_THREADS = 3;
// The number of threads to use if lifecycle thread pool is enabled, dependent on the number of
@@ -128,9 +127,6 @@ public final class SystemServiceManager implements Dumpable {
mContext = context;
mServices = new ArrayList<>();
mServiceClassnames = new ArraySet<>();
- // Disable using the thread pool for low ram devices
- sUseLifecycleThreadPool = sUseLifecycleThreadPool
- && !ActivityManager.isLowRamDeviceStatic();
mNumUserPoolThreads = Math.min(Runtime.getRuntime().availableProcessors(),
DEFAULT_MAX_USER_POOL_THREADS);
}
@@ -162,16 +158,17 @@ public final class SystemServiceManager implements Dumpable {
/**
* Returns true if the jar is in a test APEX.
*/
- private static boolean isJarInTestApex(String pathStr) {
+ private boolean isJarInTestApex(String pathStr) {
Path path = Paths.get(pathStr);
if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) {
String apexModuleName = path.getName(1).toString();
ApexManager apexManager = ApexManager.getInstance();
String packageName = apexManager.getActivePackageNameForApexModuleName(apexModuleName);
- PackageInfo packageInfo = apexManager.getPackageInfo(
- packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
- if (packageInfo != null) {
+ try {
+ PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(packageName,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
+ } catch (Exception ignore) {
}
}
return false;
@@ -549,16 +546,10 @@ public final class SystemServiceManager implements Dumpable {
terminated = threadPool.awaitTermination(
USER_POOL_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} catch (InterruptedException e) {
- Slog.wtf(TAG, "User lifecycle thread pool was interrupted while awaiting completion"
- + " of " + onWhat + " of user " + curUser, e);
- if (!onWhat.equals(USER_COMPLETED_EVENT)) {
- Slog.e(TAG, "Couldn't terminate, disabling thread pool. "
- + "Please capture a bug report.");
- sUseLifecycleThreadPool = false;
- }
+ logFailure(onWhat, curUser, "(user lifecycle threadpool was interrupted)", e);
}
if (!terminated) {
- Slog.wtf(TAG, "User lifecycle thread pool was not terminated.");
+ logFailure(onWhat, curUser, "(user lifecycle threadpool was not terminated)", null);
}
}
t.traceEnd(); // main entry
@@ -573,9 +564,9 @@ public final class SystemServiceManager implements Dumpable {
private boolean useThreadPool(int userId, @NonNull String onWhat) {
switch (onWhat) {
case USER_STARTING:
- // Limit the lifecycle parallelization to all users other than the system user
- // and only for the user start lifecycle phase for now.
- return sUseLifecycleThreadPool && userId != UserHandle.USER_SYSTEM;
+ // Don't allow lifecycle parallelization for user start on low ram devices and
+ // the system user.
+ return !ActivityManager.isLowRamDeviceStatic() && userId != UserHandle.USER_SYSTEM;
case USER_COMPLETED_EVENT:
return true;
default:
@@ -609,8 +600,6 @@ public final class SystemServiceManager implements Dumpable {
"on" + USER_STARTING + "User-" + curUserId);
} catch (Exception e) {
logFailure(USER_STARTING, curUser, serviceName, e);
- Slog.e(TAG, "Disabling thread pool - please capture a bug report.");
- sUseLifecycleThreadPool = false;
} finally {
t.traceEnd();
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 0807fbaf7cc3..0b858cf38d44 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -873,6 +873,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.registerReceiver(mBroadcastReceiver, filter);
}
+ //helper function to determine if limit on num listeners applies to callingUid
+ private boolean doesLimitApplyForListeners(int callingUid, int exemptUid) {
+ return (callingUid != Process.SYSTEM_UID
+ && callingUid != Process.PHONE_UID
+ && callingUid != exemptUid);
+ }
+
@Override
public void addOnSubscriptionsChangedListener(String callingPackage, String callingFeatureId,
IOnSubscriptionsChangedListener callback) {
@@ -887,7 +894,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
- Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), false);
+ boolean doesLimitApply = doesLimitApplyForListeners(Binder.getCallingUid(),
+ Process.myUid());
+ Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply); //
if (r == null) {
return;
@@ -941,7 +950,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
- Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), false);
+ boolean doesLimitApply = doesLimitApplyForListeners(Binder.getCallingUid(),
+ Process.myUid());
+ Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply); //
if (r == null) {
return;
@@ -1070,10 +1081,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
- boolean doesLimitApply =
- Binder.getCallingUid() != Process.SYSTEM_UID
- && Binder.getCallingUid() != Process.PHONE_UID
- && Binder.getCallingUid() != Process.myUid();
+ boolean doesLimitApply = doesLimitApplyForListeners(Binder.getCallingUid(),
+ Process.myUid());
Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
if (r == null) {
@@ -1417,7 +1426,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
.isRegistrationLimitEnabledInPlatformCompat(callingUid)) {
throw new IllegalStateException(errorMsg);
}
- } else if (doesLimitApply && numRecordsForPid
+ } else if (numRecordsForPid
>= TelephonyCallback.DEFAULT_PER_PID_REGISTRATION_LIMIT / 2) {
// Log the warning independently of the dynamically set limit -- apps shouldn't be
// doing this regardless of whether we're throwing them an exception for it.
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index e68a0a6acaf6..0afa8caf85ca 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1887,7 +1887,10 @@ final class UiModeManagerService extends SystemService {
mComputedNightMode = false;
return;
}
- resetNightModeOverrideLocked();
+ if (mNightMode != MODE_NIGHT_AUTO || (mTwilightManager != null
+ && mTwilightManager.getLastTwilightState() != null)) {
+ resetNightModeOverrideLocked();
+ }
}
private boolean resetNightModeOverrideLocked() {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76cac934fdfe..f26d9f9f49e6 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -24,7 +24,6 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
-import static android.telephony.SubscriptionManager.isValidSubscriptionId;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -168,10 +167,6 @@ public class VcnManagementService extends IVcnManagementService.Stub {
static final String VCN_CONFIG_FILE =
new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath();
- // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
-
/* Binder context for this service */
@NonNull private final Context mContext;
@NonNull private final Dependencies mDeps;
@@ -365,12 +360,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
/** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() {
- mNetworkProvider.register();
- mContext.getSystemService(ConnectivityManager.class)
- .registerNetworkCallback(
- new NetworkRequest.Builder().clearCapabilities().build(),
- mTrackingNetworkCallback);
- mTelephonySubscriptionTracker.register();
+ // Always run on the handler thread to ensure consistency.
+ mHandler.post(() -> {
+ mNetworkProvider.register();
+ mContext.getSystemService(ConnectivityManager.class)
+ .registerNetworkCallback(
+ new NetworkRequest.Builder().clearCapabilities().build(),
+ mTrackingNetworkCallback);
+ mTelephonySubscriptionTracker.register();
+ });
}
private void enforcePrimaryUser() {
@@ -511,22 +509,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
if (!mVcns.containsKey(subGrp)) {
startVcnLocked(subGrp, entry.getValue());
}
-
- // Cancel any scheduled teardowns for active subscriptions
- mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
}
}
- // Schedule teardown of any VCN instances that have lost carrier privileges (after a
- // delay)
+ // Schedule teardown of any VCN instances that have lost carrier privileges
for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
final ParcelUuid subGrp = entry.getKey();
final VcnConfig config = mConfigs.get(subGrp);
final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
- final boolean isValidActiveDataSubIdNotInVcnSubGrp =
- isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
- && !isActiveSubGroup(subGrp, snapshot);
// TODO(b/193687515): Support multiple VCNs active at the same time
if (config == null
@@ -536,31 +527,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final ParcelUuid uuidToTeardown = subGrp;
final Vcn instanceToTeardown = entry.getValue();
- // TODO(b/193687515): Support multiple VCNs active at the same time
- // If directly switching to a subscription not in the current group,
- // teardown immediately to prevent other subscription's network from being
- // outscored by the VCN. Otherwise, teardown after a delay to ensure that
- // SIM profile switches do not trigger the VCN to cycle.
- final long teardownDelayMs =
- isValidActiveDataSubIdNotInVcnSubGrp
- ? 0
- : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
- mHandler.postDelayed(() -> {
- synchronized (mLock) {
- // Guard against case where this is run after a old instance was
- // torn down, and a new instance was started. Verify to ensure
- // correct instance is torn down. This could happen as a result of a
- // Carrier App manually removing/adding a VcnConfig.
- if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
- stopVcnLocked(uuidToTeardown);
-
- // TODO(b/181789060): invoke asynchronously after Vcn notifies
- // through VcnCallback
- notifyAllPermissionedStatusCallbacksLocked(
- uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
- }
- }
- }, instanceToTeardown, teardownDelayMs);
+ stopVcnLocked(uuidToTeardown);
+
+ // TODO(b/181789060): invoke asynchronously after Vcn notifies
+ // through VcnCallback
+ notifyAllPermissionedStatusCallbacksLocked(
+ uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
} else {
// If this VCN's status has not changed, update it with the new snapshot
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index c678a67e5bd3..b63a4daab88f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -399,11 +399,16 @@ public class Watchdog implements Dumpable {
// potentially hold longer running operations with no guarantees about the timeliness
// of operations there.
//
- // The shared foreground thread is the main checker. It is where we
- // will also dispatch monitor checks and do other work.
- mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
- "foreground thread");
+ // Use a custom thread to check monitors to avoid lock contention from impacted other
+ // threads.
+ ServiceThread t = new ServiceThread("watchdog.monitor",
+ android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
+ t.start();
+ mMonitorChecker = new HandlerChecker(new Handler(t.getLooper()), "monitor thread");
mHandlerCheckers.add(withDefaultTimeout(mMonitorChecker));
+
+ mHandlerCheckers.add(withDefaultTimeout(
+ new HandlerChecker(FgThread.getHandler(), "foreground thread")));
// Add checker for main thread. We only do a quick check since there
// can be UI running on the thread.
mHandlerCheckers.add(withDefaultTimeout(
@@ -867,6 +872,7 @@ public class Watchdog implements Dumpable {
if (halfWatchdog) {
dropboxTag = "pre_watchdog";
CriticalEventLog.getInstance().logHalfWatchdog(subject);
+ FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_PRE_WATCHDOG_OCCURRED);
} else {
dropboxTag = "watchdog";
CriticalEventLog.getInstance().logWatchdog(subject, errorId);
@@ -879,7 +885,7 @@ public class Watchdog implements Dumpable {
long anrTime = SystemClock.uptimeMillis();
StringBuilder report = new StringBuilder();
- report.append(MemoryPressureUtil.currentPsiState());
+ report.append(ResourcePressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false);
StringWriter tracesFileException = new StringWriter();
final File stack = ActivityManagerService.dumpStackTraces(
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b059cc7e2aa2..6b731c319c4b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -168,8 +168,8 @@ public class AccountManagerService
}
@Override
- public void onUserStopping(@NonNull TargetUser user) {
- Slog.i(TAG, "onStopUser " + user);
+ public void onUserStopped(@NonNull TargetUser user) {
+ Slog.i(TAG, "onUserStopped " + user);
mService.purgeUserData(user.getUserIdentifier());
}
}
@@ -1820,6 +1820,14 @@ public class AccountManagerService
if (account == null) {
return false;
}
+ if (account.name != null && account.name.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
+ if (account.type != null && account.type.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
if (!isLocalUnlockedUser(accounts.userId)) {
Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
+ accounts.userId + " is locked. callingUid=" + callingUid);
@@ -2065,6 +2073,10 @@ public class AccountManagerService
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
+ if (newName != null && newName.length() > 200) {
+ Log.e(TAG, "renameAccount failed - account name longer than 200");
+ throw new IllegalArgumentException("account name longer than 200");
+ }
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
String msg = String.format(
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 297d28dadde3..ad89afb791cc 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -892,15 +892,6 @@ public class AdbDebuggingManager {
case MESSAGE_ADB_CONFIRM: {
String key = (String) msg.obj;
- if ("trigger_restart_min_framework".equals(
- SystemProperties.get("vold.decrypt"))) {
- Slog.w(TAG, "Deferring adb confirmation until after vold decrypt");
- if (mThread != null) {
- mThread.sendResponse("NO");
- logAdbConnectionChanged(key, AdbProtoEnums.DENIED_VOLD_DECRYPT, false);
- }
- break;
- }
String fingerprints = getFingerprints(key);
if ("".equals(fingerprints)) {
if (mThread != null) {
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 6667d1b45027..5d0c732d5f48 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -56,6 +56,7 @@ import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.testharness.TestHarnessModeService;
import java.io.File;
import java.io.FileDescriptor;
@@ -163,18 +164,8 @@ public class AdbService extends IAdbManager.Stub {
}
}
- private void initAdbState() {
+ private void registerContentObservers() {
try {
- /*
- * Use the normal bootmode persistent prop to maintain state of adb across
- * all boot modes.
- */
- mIsAdbUsbEnabled = containsFunction(
- SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
- UsbManager.USB_FUNCTION_ADB);
- mIsAdbWifiEnabled = "1".equals(
- SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
-
// register observer to listen for settings changes
mObserver = new AdbSettingsObserver();
mContentResolver.registerContentObserver(
@@ -184,7 +175,7 @@ public class AdbService extends IAdbManager.Stub {
Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
false, mObserver);
} catch (Exception e) {
- Slog.e(TAG, "Error in initAdbState", e);
+ Slog.e(TAG, "Error in registerContentObservers", e);
}
}
@@ -248,7 +239,7 @@ public class AdbService extends IAdbManager.Stub {
mContentResolver = context.getContentResolver();
mDebuggingManager = new AdbDebuggingManager(context);
- initAdbState();
+ registerContentObservers();
LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
}
@@ -259,10 +250,23 @@ public class AdbService extends IAdbManager.Stub {
public void systemReady() {
if (DEBUG) Slog.d(TAG, "systemReady");
+ /*
+ * Use the normal bootmode persistent prop to maintain state of adb across
+ * all boot modes.
+ */
+ mIsAdbUsbEnabled = containsFunction(
+ SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
+ UsbManager.USB_FUNCTION_ADB);
+ boolean shouldEnableAdbUsb = mIsAdbUsbEnabled
+ || SystemProperties.getBoolean(
+ TestHarnessModeService.TEST_HARNESS_MODE_PROPERTY, false);
+ mIsAdbWifiEnabled = "1".equals(
+ SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
+
// make sure the ADB_ENABLED setting value matches the current state
try {
Settings.Global.putInt(mContentResolver,
- Settings.Global.ADB_ENABLED, mIsAdbUsbEnabled ? 1 : 0);
+ Settings.Global.ADB_ENABLED, shouldEnableAdbUsb ? 1 : 0);
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0);
} catch (SecurityException e) {
@@ -272,7 +276,7 @@ public class AdbService extends IAdbManager.Stub {
}
/**
- * Callend in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
+ * Called in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
*/
public void bootCompleted() {
if (DEBUG) Slog.d(TAG, "boot completed");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 71682f26e664..f8b6bef01fc1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -49,6 +49,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
@@ -311,7 +312,6 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.server.ServerProtoEnums;
import android.sysprop.InitProperties;
-import android.sysprop.VoldProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
@@ -415,6 +415,7 @@ import com.android.server.uri.GrantUri;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.PriorityDump;
+import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.ActivityMetricsLaunchObserver;
@@ -2297,13 +2298,9 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAppOpsManager;
}
- /**
- * Provides the basic functionality for activity task related tests when a handler thread is
- * given to initialize the dependency members.
- */
+ /** Provides the basic functionality for unit tests. */
@VisibleForTesting
- public ActivityManagerService(Injector injector, ServiceThread handlerThread) {
- final boolean hasHandlerThread = handlerThread != null;
+ ActivityManagerService(Injector injector, @NonNull ServiceThread handlerThread) {
mInjector = injector;
mContext = mInjector.getContext();
mUiContext = null;
@@ -2311,33 +2308,27 @@ public class ActivityManagerService extends IActivityManager.Stub
mPackageWatchdog = null;
mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
mBatteryStatsService = null;
- mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null;
+ mHandler = new MainHandler(handlerThread.getLooper());
mHandlerThread = handlerThread;
- mConstants = hasHandlerThread
- ? new ActivityManagerConstants(mContext, this, mHandler) : null;
+ mConstants = new ActivityManagerConstants(mContext, this, mHandler);
final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
mPlatformCompat = null;
mProcessList = injector.getProcessList(this);
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = hasHandlerThread
- ? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
+ mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
- mIntentFirewall = hasHandlerThread
- ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
+ mIntentFirewall = null;
mProcessStats = null;
mCpHelper = new ContentProviderHelper(this, false);
- // For the usage of {@link ActiveServices#cleanUpServices} that may be invoked from
- // {@link ActivityTaskSupervisor#cleanUpRemovedTaskLocked}.
- mServices = hasHandlerThread ? new ActiveServices(this) : null;
+ mServices = null;
mSystemThread = null;
mUiHandler = injector.getUiHandler(null /* service */);
mUidObserverController = new UidObserverController(mUiHandler);
- mUserController = hasHandlerThread ? new UserController(this) : null;
- mPendingIntentController = hasHandlerThread
- ? new PendingIntentController(handlerThread.getLooper(), mUserController,
- mConstants) : null;
+ mUserController = new UserController(this);
+ mPendingIntentController =
+ new PendingIntentController(handlerThread.getLooper(), mUserController, mConstants);
mAppRestrictionController = new AppRestrictionController(mContext, this);
mProcStartHandlerThread = null;
mProcStartHandler = null;
@@ -2346,7 +2337,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mFactoryTest = FACTORY_TEST_OFF;
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
- mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mPendingStartActivityUids = new PendingStartActivityUids();
mUseFifoUiScheduling = false;
mEnableOffloadQueue = false;
mFgBroadcastQueue = mBgBroadcastQueue = mBgOffloadBroadcastQueue =
@@ -2482,7 +2473,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mInternal = new LocalService();
- mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mPendingStartActivityUids = new PendingStartActivityUids();
mTraceErrorLogger = new TraceErrorLogger();
mComponentAliasResolver = new ComponentAliasResolver(this);
}
@@ -4299,12 +4290,19 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
}
+ final int userId = UserHandle.getUserId(uid);
+ final int[] broadcastAllowList =
+ getPackageManagerInternal().getVisibilityAllowList(packageName, userId);
intent.putExtra(Intent.EXTRA_UID, uid);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
- broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.getUserId(uid));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null /* callerApp */, null /* callerPackage */,
+ null /* callerFeatureId */, intent, null /* resolvedType */, null /* resultTo */,
+ 0 /* resultCode */, null /* resultData */, null /* resultExtras */,
+ null /* requiredPermissions */, null /* excludedPermissions */,
+ null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
+ false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId, false /* allowBackgroundActivityStarts */,
+ null /* backgroundActivityStartsToken */, broadcastAllowList);
}
private void cleanupDisabledPackageComponentsLocked(
@@ -5141,12 +5139,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
-
- // And trigger dev.bootcomplete if we are not showing encryption progress
- if (!"trigger_restart_min_framework".equals(VoldProperties.decrypt().orElse(""))
- || "".equals(VoldProperties.encrypt_progress().orElse(""))) {
- SystemProperties.set("dev.bootcomplete", "1");
- }
+ SystemProperties.set("dev.bootcomplete", "1");
mUserController.sendBootCompleted(
new IIntentReceiver.Stub() {
@Override
@@ -8177,8 +8170,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// do this when the system user is not setup since the setup wizard should be the one
// to handle home activity in this case.
if (UserManager.isSplitSystemUser() &&
- Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0) != 0
+ Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, currentUserId) != 0
|| SystemProperties.getBoolean(SYSTEM_USER_HOME_NEEDED, false)) {
t.traceBegin("enableHomeActivity");
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
@@ -8808,8 +8801,8 @@ public class ActivityManagerService extends IActivityManager.Stub
sb.append("Foreground: ")
.append(process.isInterestingToUserLocked() ? "Yes" : "No")
.append("\n");
- if (process.getStartTime() > 0) {
- long runtimeMillis = SystemClock.elapsedRealtime() - process.getStartTime();
+ if (process.getStartUptime() > 0) {
+ long runtimeMillis = SystemClock.uptimeMillis() - process.getStartUptime();
sb.append("Process-Runtime: ").append(runtimeMillis).append("\n");
}
}
@@ -9548,7 +9541,7 @@ public class ActivityManagerService extends IActivityManager.Stub
opti++;
}
synchronized (this) {
- dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
+ dumpBroadcastsLocked(fd, pw, args, opti, /* dumpAll= */ true, dumpPackage);
}
} else if ("broadcast-stats".equals(cmd)) {
if (opti < args.length) {
@@ -10487,6 +10480,8 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean needSep = false;
boolean onlyHistory = false;
boolean printedAnything = false;
+ boolean onlyReceivers = false;
+ int filteredUid = Process.INVALID_UID;
if ("history".equals(dumpPackage)) {
if (opti < args.length && "-s".equals(args[opti])) {
@@ -10495,6 +10490,31 @@ public class ActivityManagerService extends IActivityManager.Stub
onlyHistory = true;
dumpPackage = null;
}
+ if ("receivers".equals(dumpPackage)) {
+ onlyReceivers = true;
+ dumpPackage = null;
+ if (opti + 2 <= args.length) {
+ for (int i = opti; i < args.length; i++) {
+ String arg = args[i];
+ switch (arg) {
+ case "--uid":
+ filteredUid = getIntArg(pw, args, ++i, Process.INVALID_UID);
+ if (filteredUid == Process.INVALID_UID) {
+ return;
+ }
+ break;
+ default:
+ pw.printf("Invalid argument at index %d: %s\n", i, arg);
+ return;
+ }
+ }
+ }
+ }
+ if (DEBUG_BROADCAST) {
+ Slogf.d(TAG_BROADCAST, "dumpBroadcastsLocked(): dumpPackage=%s, onlyHistory=%b, "
+ + "onlyReceivers=%b, filteredUid=%d", dumpPackage, onlyHistory, onlyReceivers,
+ filteredUid);
+ }
pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)");
if (!onlyHistory && dumpAll) {
@@ -10507,6 +10527,13 @@ public class ActivityManagerService extends IActivityManager.Stub
!dumpPackage.equals(r.app.info.packageName))) {
continue;
}
+ if (filteredUid != Process.INVALID_UID && filteredUid != r.app.uid) {
+ if (DEBUG_BROADCAST) {
+ Slogf.v(TAG_BROADCAST, "dumpBroadcastsLocked(): skipping receiver whose"
+ + " uid (%d) is not %d: %s", r.app.uid, filteredUid, r.app);
+ }
+ continue;
+ }
if (!printed) {
pw.println(" Registered Receivers:");
needSep = true;
@@ -10516,24 +10543,32 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(" * "); pw.println(r);
r.dump(pw, " ");
}
+ } else {
+ if (onlyReceivers) {
+ pw.println(" (no registered receivers)");
+ }
}
- if (mReceiverResolver.dump(pw, needSep ?
- "\n Receiver Resolver Table:" : " Receiver Resolver Table:",
- " ", dumpPackage, false, false)) {
- needSep = true;
- printedAnything = true;
+ if (!onlyReceivers) {
+ if (mReceiverResolver.dump(pw, needSep
+ ? "\n Receiver Resolver Table:" : " Receiver Resolver Table:",
+ " ", dumpPackage, false, false)) {
+ needSep = true;
+ printedAnything = true;
+ }
}
}
- for (BroadcastQueue q : mBroadcastQueues) {
- needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
- printedAnything |= needSep;
+ if (!onlyReceivers) {
+ for (BroadcastQueue q : mBroadcastQueues) {
+ needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
+ printedAnything |= needSep;
+ }
}
needSep = true;
- if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
+ if (!onlyHistory && !onlyReceivers && mStickyBroadcasts != null && dumpPackage == null) {
for (int user=0; user<mStickyBroadcasts.size(); user++) {
if (needSep) {
pw.println();
@@ -10568,7 +10603,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (!onlyHistory && dumpAll) {
+ if (!onlyHistory && !onlyReceivers && dumpAll) {
pw.println();
for (BroadcastQueue queue : mBroadcastQueues) {
pw.println(" mBroadcastsScheduled [" + queue.mQueueName + "]="
@@ -14538,6 +14573,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (arguments != null && arguments.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
+ final IPackageManager pm = AppGlobals.getPackageManager();
synchronized(this) {
InstrumentationInfo ii = null;
@@ -14546,11 +14582,8 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean noRestart = (flags & INSTR_FLAG_NO_RESTART) != 0;
try {
- ii = mContext.getPackageManager().getInstrumentationInfo(
- className, STOCK_PM_FLAGS);
- ai = AppGlobals.getPackageManager().getApplicationInfo(
- ii.targetPackage, STOCK_PM_FLAGS, userId);
- } catch (PackageManager.NameNotFoundException e) {
+ ii = pm.getInstrumentationInfoAsUser(className, STOCK_PM_FLAGS, userId);
+ ai = pm.getApplicationInfo(ii.targetPackage, STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
}
if (ii == null) {
@@ -14576,8 +14609,11 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- int match = mContext.getPackageManager().checkSignatures(
- ii.targetPackage, ii.packageName);
+ int match = SIGNATURE_NO_MATCH;
+ try {
+ match = pm.checkSignatures(ii.targetPackage, ii.packageName, userId);
+ } catch (RemoteException e) {
+ }
if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
if (Build.IS_DEBUGGABLE && (callingUid == Process.ROOT_UID)
&& (flags & INSTR_FLAG_ALWAYS_CHECK_SIGNATURE) == 0) {
@@ -16723,7 +16759,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final WindowProcessController wpc =
(WindowProcessController) procsToKill.get(i);
final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
- if (pr.mState.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND
+ if (ActivityManager.isProcStateBackground(pr.mState.getSetProcState())
&& pr.mReceivers.numberOfCurReceivers() == 0) {
pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
@@ -17373,7 +17409,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// next top activity on time. This race will fail the following binder transactions WM
// sends to the activity. After this race issue between WM/ATMS and AMS is solved, this
// workaround can be removed. (b/213288355)
- if (isNewPending && mOomAdjuster != null) { // It can be null in unit test.
+ if (isNewPending) {
mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid);
}
// We need to update the network rules for the app coming to the top state so that
@@ -18470,4 +18506,24 @@ public class ActivityManagerService extends IActivityManager.Stub
Trace.traceBegin(traceTag, methodName + subInfo);
}
}
+
+ /**
+ * Gets an {@code int} argument from the given {@code index} on {@code args}, logging an error
+ * message on {@code pw} when it cannot be parsed.
+ *
+ * Returns {@code int} argument or {@code invalidValue} if it could not be parsed.
+ */
+ private static int getIntArg(PrintWriter pw, String[] args, int index, int invalidValue) {
+ if (index > args.length) {
+ pw.println("Missing argument");
+ return invalidValue;
+ }
+ String arg = args[index];
+ try {
+ return Integer.parseInt(arg);
+ } catch (Exception e) {
+ pw.printf("Non-numeric argument at index %d: %s\n", index, arg);
+ return invalidValue;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 2c2579f9e504..2ec744fd4bb8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -183,7 +183,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
private boolean mAsync;
private BroadcastOptions mBroadcastOptions;
private boolean mShowSplashScreen;
- private boolean mDismissKeyguardIfInsecure;
+ private boolean mDismissKeyguard;
final boolean mDumping;
@@ -442,8 +442,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
mAsync = true;
} else if (opt.equals("--splashscreen-show-icon")) {
mShowSplashScreen = true;
- } else if (opt.equals("--dismiss-keyguard-if-insecure")) {
- mDismissKeyguardIfInsecure = true;
+ } else if (opt.equals("--dismiss-keyguard")) {
+ mDismissKeyguard = true;
} else {
return false;
}
@@ -588,11 +588,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
}
- if (mDismissKeyguardIfInsecure) {
+ if (mDismissKeyguard) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
- options.setDismissKeyguardIfInsecure();
+ options.setDismissKeyguard();
}
if (mWaitOption) {
result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java
index 5506ad1b245b..9be553c49a35 100644
--- a/services/core/java/com/android/server/am/ActivityManagerUtils.java
+++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java
@@ -16,6 +16,7 @@
package com.android.server.am;
import android.app.ActivityThread;
+import android.content.ContentResolver;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -53,9 +54,12 @@ public class ActivityManagerUtils {
static int getAndroidIdHash() {
// No synchronization is required. Double-initialization is fine here.
if (sAndroidIdHash == null) {
- final String androidId = Settings.Secure.getString(
- ActivityThread.currentApplication().getContentResolver(),
- Settings.Secure.ANDROID_ID);
+ final ContentResolver resolver = ActivityThread.currentApplication()
+ .getContentResolver();
+ final String androidId = Settings.Secure.getStringForUser(
+ resolver,
+ Settings.Secure.ANDROID_ID,
+ resolver.getUserId());
sAndroidIdHash = getUnsignedHashUnCached(
sInjectedAndroidId != null ? sInjectedAndroidId : androidId);
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e7fcc5989467..c65e61a2b60f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1554,14 +1554,22 @@ public class OomAdjuster {
boolean foregroundActivities = false;
boolean hasVisibleActivities = false;
- if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
+ if (app == topApp && (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP
+ || PROCESS_STATE_CUR_TOP == PROCESS_STATE_IMPORTANT_FOREGROUND)) {
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
- state.setAdjType("top-activity");
+ if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP) {
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ state.setAdjType("top-activity");
+ } else {
+ // Demote the scheduling group to avoid CPU contention if there is another more
+ // important process which also uses top-app, such as if SystemUI is animating.
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ state.setAdjType("intermediate-top-activity");
+ }
foregroundActivities = true;
hasVisibleActivities = true;
- procState = PROCESS_STATE_CUR_TOP;
+ procState = PROCESS_STATE_TOP;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
}
@@ -2605,7 +2613,7 @@ public class OomAdjuster {
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
- && state.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND) {
+ && ActivityManager.isProcStateBackground(state.getSetProcState())) {
app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
success = false;
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index bd600571f0a3..da09317add90 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -16,7 +16,6 @@
package com.android.server.am;
-import android.content.Context;
import android.os.SystemClock;
import android.util.Pair;
import android.util.Slog;
@@ -40,11 +39,6 @@ final class PendingStartActivityUids {
// Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
// uid is added.
private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
- private Context mContext;
-
- PendingStartActivityUids(Context context) {
- mContext = context;
- }
/** Returns {@code true} if the uid is put to the pending array. Otherwise it existed. */
synchronized boolean add(int uid, int pid) {
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 653ece4a883c..b27665a7e491 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -28,6 +28,7 @@ import android.app.AnrController;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
@@ -50,7 +51,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.MemoryPressureUtil;
+import com.android.server.ResourcePressureUtil;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.wm.WindowProcessController;
@@ -401,7 +402,7 @@ class ProcessErrorStateRecord {
}
StringBuilder report = new StringBuilder();
- report.append(MemoryPressureUtil.currentPsiState());
+ report.append(ResourcePressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
// don't dump native PIDs for background ANRs unless it is the process of interest
@@ -626,8 +627,11 @@ class ProcessErrorStateRecord {
}
private boolean getShowBackground() {
- return Settings.Secure.getInt(mService.mContext.getContentResolver(),
- Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+ final ContentResolver resolver = mService.mContext.getContentResolver();
+ return Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.ANR_SHOW_BACKGROUND,
+ 0,
+ resolver.getUserId()) != 0;
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a2048a347c7c..0d9463958276 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2309,8 +2309,8 @@ public final class ProcessList {
if (!regularZygote) {
// webview and app zygote don't have the permission to create the nodes
if (Process.createProcessGroup(uid, startResult.pid) < 0) {
- Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
- + app.processName + " (" + startResult.pid + ")");
+ throw new AssertionError("Unable to create process group for " + app.processName
+ + " (" + startResult.pid + ")");
}
}
diff --git a/services/core/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
index ff34fd36de3e..f3d8ba1564fa 100644
--- a/services/core/java/com/android/server/am/ReceiverList.java
+++ b/services/core/java/com/android/server/am/ReceiverList.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.annotation.Nullable;
import android.content.IIntentReceiver;
import android.content.IntentFilter;
import android.os.Binder;
@@ -37,7 +38,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter>
implements IBinder.DeathRecipient {
final ActivityManagerService owner;
public final IIntentReceiver receiver;
- public final ProcessRecord app;
+ public final @Nullable ProcessRecord app;
public final int pid;
public final int uid;
public final int userId;
@@ -46,7 +47,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter>
String stringName;
- ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
+ ReceiverList(ActivityManagerService _owner, @Nullable ProcessRecord _app,
int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
owner = _owner;
receiver = _receiver;
@@ -82,7 +83,10 @@ final class ReceiverList extends ArrayList<BroadcastFilter>
void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- app.dumpDebug(proto, ReceiverListProto.APP);
+ if (app != null) {
+ app.dumpDebug(proto, ReceiverListProto.APP);
+ proto.write(ReceiverListProto.NUMBER_RECEIVERS, app.mReceivers.numberOfReceivers());
+ }
proto.write(ReceiverListProto.PID, pid);
proto.write(ReceiverListProto.UID, uid);
proto.write(ReceiverListProto.USER, userId);
@@ -101,8 +105,12 @@ final class ReceiverList extends ArrayList<BroadcastFilter>
void dumpLocal(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("app="); pw.print(app != null ? app.toShortString() : null);
- pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid);
- pw.print(" user="); pw.println(userId);
+ pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid);
+ pw.print(" user="); pw.print(userId);
+ if (app != null) {
+ pw.print(" #receivers="); pw.print(app.mReceivers.numberOfReceivers());
+ }
+ pw.println();
if (curBroadcast != null || linkedToDeath) {
pw.print(prefix); pw.print("curBroadcast="); pw.print(curBroadcast);
pw.print(" linkedToDeath="); pw.println(linkedToDeath);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 2dadcecc9f1f..5b80f40aa2c0 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -86,6 +86,7 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_LMKD_NATIVE,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
+ DeviceConfig.NAMESPACE_MGLRU_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
DeviceConfig.NAMESPACE_NNAPI_NATIVE,
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
@@ -240,7 +241,7 @@ public class SettingsToPropertiesMapper {
}
value = "";
} else if (value.length() > SYSTEM_PROPERTY_MAX_LENGTH) {
- log(value + " exceeds system property max length.");
+ log("key=" + key + " value=" + value + " exceeds system property max length.");
return;
}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index e2b22dc1bd3d..ec6c2f00b3b1 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -21,12 +21,12 @@ import static java.lang.System.out;
import android.annotation.NonNull;
import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
+import android.app.ambientcontext.AmbientContextManager;
import android.content.ComponentName;
import android.os.Binder;
import android.os.RemoteCallback;
import android.os.ShellCommand;
import android.service.ambientcontext.AmbientContextDetectionResult;
-import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
import java.io.PrintWriter;
@@ -51,13 +51,13 @@ final class AmbientContextShellCommand extends ShellCommand {
/** Callbacks for AmbientContextEventService results used internally for testing. */
static class TestableCallbackInternal {
private AmbientContextDetectionResult mLastResult;
- private AmbientContextDetectionServiceStatus mLastStatus;
+ private int mLastStatus;
public AmbientContextDetectionResult getLastResult() {
return mLastResult;
}
- public AmbientContextDetectionServiceStatus getLastStatus() {
+ public int getLastStatus() {
return mLastStatus;
}
@@ -80,13 +80,10 @@ final class AmbientContextShellCommand extends ShellCommand {
@NonNull
private RemoteCallback createRemoteStatusCallback() {
return new RemoteCallback(result -> {
- AmbientContextDetectionServiceStatus status =
- (AmbientContextDetectionServiceStatus) result.get(
- AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
+ int status = result.getInt(AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY);
final long token = Binder.clearCallingIdentity();
try {
mLastStatus = status;
- out.println("Status available: " + status);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -110,8 +107,6 @@ final class AmbientContextShellCommand extends ShellCommand {
return runStopDetection();
case "get-last-status-code":
return getLastStatusCode();
- case "get-last-package-name":
- return getLastPackageName();
case "query-service-status":
return runQueryServiceStatus();
case "get-bound-package":
@@ -126,7 +121,8 @@ final class AmbientContextShellCommand extends ShellCommand {
private int runStartDetection() {
final int userId = Integer.parseInt(getNextArgRequired());
final String packageName = getNextArgRequired();
- mService.startDetection(userId, REQUEST, packageName,
+ mService.startDetection(
+ userId, REQUEST, packageName,
sTestableCallbackInternal.createRemoteDetectionResultCallback(),
sTestableCallbackInternal.createRemoteStatusCallback());
return 0;
@@ -151,18 +147,9 @@ final class AmbientContextShellCommand extends ShellCommand {
}
private int getLastStatusCode() {
- AmbientContextDetectionServiceStatus lastResponse =
- sTestableCallbackInternal.getLastStatus();
- if (lastResponse == null) {
- return -1;
- }
- return lastResponse.getStatusCode();
- }
-
- private int getLastPackageName() {
- AmbientContextDetectionServiceStatus lastResponse =
- sTestableCallbackInternal.getLastStatus();
- out.println(lastResponse == null ? "" : lastResponse.getPackageName());
+ final PrintWriter resultPrinter = getOutPrintWriter();
+ int lastStatus = sTestableCallbackInternal.getLastStatus();
+ resultPrinter.println(lastStatus);
return 0;
}
@@ -174,22 +161,21 @@ final class AmbientContextShellCommand extends ShellCommand {
pw.println(" Print this help text.");
pw.println();
pw.println(" start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
- pw.println(" stop-detection USER_ID: Stops AmbientContextEvent detection.");
+ pw.println(" stop-detection USER_ID PACKAGE_NAME: Stops AmbientContextEvent detection.");
pw.println(" get-last-status-code: Prints the latest request status code.");
- pw.println(" get-last-package-name: Prints the latest request package name.");
- pw.println(" query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
+ pw.println(" query-service-status USER_ID PACKAGE_NAME: Prints the service status code.");
pw.println(" get-bound-package USER_ID:"
+ " Print the bound package that implements the service.");
- pw.println(" set-temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" set-temporary-service USER_ID [PACKAGE_NAME] [COMPONENT_NAME DURATION]");
pw.println(" Temporarily (for DURATION ms) changes the service implementation.");
pw.println(" To reset, call with just the USER_ID argument.");
}
private int getBoundPackageName() {
- final PrintWriter out = getOutPrintWriter();
+ final PrintWriter resultPrinter = getOutPrintWriter();
final int userId = Integer.parseInt(getNextArgRequired());
final ComponentName componentName = mService.getComponentName(userId);
- out.println(componentName == null ? "" : componentName.getPackageName());
+ resultPrinter.println(componentName == null ? "" : componentName.getPackageName());
return 0;
}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 4fd739ca5e3e..0f5aa3a08950 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -16,10 +16,11 @@
package com.android.server.app;
-import android.Manifest;
+import static android.Manifest.permission.MANAGE_GAME_ACTIVITY;
+
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
@@ -181,10 +182,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final IGameServiceController mGameServiceController =
new IGameServiceController.Stub() {
@Override
- @RequiresPermission(Manifest.permission.MANAGE_GAME_ACTIVITY)
+ @EnforcePermission(MANAGE_GAME_ACTIVITY)
public void createGameSession(int taskId) {
- mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
- "createGameSession()");
mBackgroundExecutor.execute(() -> {
GameServiceProviderInstanceImpl.this.createGameSession(taskId);
});
@@ -194,11 +193,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final IGameSessionController mGameSessionController =
new IGameSessionController.Stub() {
@Override
- @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
+ @EnforcePermission(MANAGE_GAME_ACTIVITY)
public void takeScreenshot(int taskId,
@NonNull AndroidFuture gameScreenshotResultFuture) {
- mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
- "takeScreenshot()");
mBackgroundExecutor.execute(() -> {
GameServiceProviderInstanceImpl.this.takeScreenshot(taskId,
gameScreenshotResultFuture);
@@ -206,10 +203,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
@Override
- @RequiresPermission(Manifest.permission.MANAGE_GAME_ACTIVITY)
+ @EnforcePermission(MANAGE_GAME_ACTIVITY)
public void restartGame(int taskId) {
- mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
- "restartGame()");
mBackgroundExecutor.execute(() -> {
GameServiceProviderInstanceImpl.this.restartGame(taskId);
});
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 27ce493f717f..86da39b07c0c 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -210,6 +210,9 @@ public final class AppHibernationService extends SystemService {
* package manager from re-optimizing the APK.
*/
private boolean isOatArtifactDeletionEnabled() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
return mOatArtifactDeletionEnabled;
}
@@ -875,6 +878,11 @@ public final class AppHibernationService extends SystemService {
}
@Override
+ public boolean isOatArtifactDeletionEnabled() {
+ return mService.isOatArtifactDeletionEnabled();
+ }
+
+ @Override
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err, @NonNull String[] args,
@Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index b56654fd7b9a..5c7af47682e4 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2786,7 +2786,9 @@ public class AppOpsService extends IAppOpsService.Stub {
@Nullable IAppOpsCallback permissionPolicyCallback) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return;
+ }
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -3225,7 +3227,9 @@ public class AppOpsService extends IAppOpsService.Stub {
private int checkOperationImpl(int code, int uid, String packageName,
@Nullable String attributionTag, boolean raw) {
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return AppOpsManager.opToDefaultMode(code);
+ }
String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3337,8 +3341,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private boolean isPackageExisted(String packageName) {
- return LocalServices.getService(PackageManagerInternal.class)
- .getPackageStateInternal(packageName) != null;
+ return getPackageManagerInternal().getPackageStateInternal(packageName) != null;
}
/**
@@ -3373,8 +3376,11 @@ public class AppOpsService extends IAppOpsService.Stub {
verifyIncomingProxyUid(attributionSource);
verifyIncomingOp(code);
- verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
- verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
+ if (!isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))
+ || !isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))) {
+ return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, proxiedAttributionTag,
+ proxiedPackageName);
+ }
skipProxyOperation = skipProxyOperation
&& isCallerAndAttributionTrusted(attributionSource);
@@ -3431,7 +3437,10 @@ public class AppOpsService extends IAppOpsService.Stub {
@Nullable String message, boolean shouldCollectMessage) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
+ packageName);
+ }
String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3837,7 +3846,10 @@ public class AppOpsService extends IAppOpsService.Stub {
int attributionChainId) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
+ packageName);
+ }
String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3891,8 +3903,11 @@ public class AppOpsService extends IAppOpsService.Stub {
verifyIncomingProxyUid(attributionSource);
verifyIncomingOp(code);
- verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
- verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+ if (!isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))
+ || !isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))) {
+ return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, proxiedAttributionTag,
+ proxiedPackageName);
+ }
boolean isCallerTrusted = isCallerAndAttributionTrusted(attributionSource);
skipProxyOperation = isCallerTrusted && skipProxyOperation;
@@ -4078,7 +4093,9 @@ public class AppOpsService extends IAppOpsService.Stub {
String attributionTag) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return;
+ }
String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -4111,8 +4128,10 @@ public class AppOpsService extends IAppOpsService.Stub {
verifyIncomingProxyUid(attributionSource);
verifyIncomingOp(code);
- verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
- verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+ if (!isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))
+ || !isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))) {
+ return null;
+ }
String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid,
proxyPackageName);
@@ -4406,12 +4425,32 @@ public class AppOpsService extends IAppOpsService.Stub {
throw new IllegalArgumentException("Bad operation #" + op);
}
- private void verifyIncomingPackage(@Nullable String packageName, @UserIdInt int userId) {
- if (packageName != null && getPackageManagerInternal().filterAppAccess(packageName,
- Binder.getCallingUid(), userId)) {
- throw new IllegalArgumentException(
- packageName + " not found from " + Binder.getCallingUid());
+ private boolean isIncomingPackageValid(@Nullable String packageName, @UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ // Handle the special UIDs that don't have actual packages (audioserver, cameraserver, etc).
+ if (packageName == null || isSpecialPackage(callingUid, packageName)) {
+ return true;
}
+
+ // If the package doesn't exist, #verifyAndGetBypass would throw a SecurityException in
+ // the end. Although that exception would be caught and return, we could make it return
+ // early.
+ if (!isPackageExisted(packageName)) {
+ return false;
+ }
+
+ if (getPackageManagerInternal().filterAppAccess(packageName, callingUid, userId)) {
+ Slog.w(TAG, packageName + " not found from " + callingUid);
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean isSpecialPackage(int callingUid, @Nullable String packageName) {
+ final String resolvedPackage = AppOpsManager.resolvePackageName(callingUid, packageName);
+ return callingUid == Process.SYSTEM_UID
+ || resolveUid(resolvedPackage) != Process.INVALID_UID;
}
private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
@@ -6706,7 +6745,9 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+ return false;
+ }
final String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -7112,7 +7153,7 @@ public class AppOpsService extends IAppOpsService.Stub {
private static int resolveUid(String packageName) {
if (packageName == null) {
- return -1;
+ return Process.INVALID_UID;
}
switch (packageName) {
case "root":
@@ -7127,7 +7168,7 @@ public class AppOpsService extends IAppOpsService.Stub {
case "cameraserver":
return Process.CAMERASERVER_UID;
}
- return -1;
+ return Process.INVALID_UID;
}
private static String[] getPackagesForUid(int uid) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 02648c4da76f..90b2bf29dc1b 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -11491,7 +11491,7 @@ public class AudioService extends IAudioService.Stub
}
}
return pids;
- } catch (RemoteException e) {
+ } catch (RemoteException | RuntimeException e) {
return new HashSet<Integer>();
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0d9b75481ea9..4767969bd3ed 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -958,7 +958,7 @@ public class BiometricService extends SystemService {
public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
- CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
+ CoexCoordinator.FACE_HAPTIC_DISABLE, 0) != 0;
}
public Supplier<Long> getRequestGenerator() {
diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS
index f05f40353e30..cd281e06f40d 100644
--- a/services/core/java/com/android/server/biometrics/OWNERS
+++ b/services/core/java/com/android/server/biometrics/OWNERS
@@ -1,9 +1,14 @@
set noparent
-kchyn@google.com
-jaggies@google.com
-curtislb@google.com
+graciecheng@google.com
ilyamaty@google.com
-joshmccloskey@google.com
+jaggies@google.com
jbolinger@google.com
-graciecheng@google.com
+jeffpu@google.com
+joshmccloskey@google.com
+
+firewall@google.com
+jasonsfchang@google.com
+lbill@google.com
+mingjuwu@google.com
+
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 0d755213da07..06417d725e7e 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -54,6 +54,7 @@ import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.Binder;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -65,6 +66,7 @@ import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import java.util.ArrayList;
import java.util.List;
public class Utils {
@@ -88,6 +90,40 @@ public class Utils {
return true;
}
+ /** If virtualized biometrics are supported (requires debug build). */
+ public static boolean isVirtualEnabled(@NonNull Context context) {
+ return Build.isDebuggable()
+ && Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * Get the enabled HAL instances. If virtual is enabled and available it will be returned as
+ * the only instance, otherwise all other instances will be returned.
+ *
+ * @param context system context
+ * @param declaredInstances known instances
+ * @return filtered list of enabled instances
+ */
+ @NonNull
+ public static List<String> filterAvailableHalInstances(@NonNull Context context,
+ @NonNull List<String> declaredInstances) {
+ if (declaredInstances.size() <= 1) {
+ return declaredInstances;
+ }
+
+ final int virtualAt = declaredInstances.indexOf("virtual");
+ if (isVirtualEnabled(context) && virtualAt != -1) {
+ return List.of(declaredInstances.get(virtualAt));
+ }
+
+ declaredInstances = new ArrayList<>(declaredInstances);
+ if (virtualAt != -1) {
+ declaredInstances.remove(virtualAt);
+ }
+ return declaredInstances;
+ }
+
/**
* Combines {@link PromptInfo#setDeviceCredentialAllowed(boolean)} with
* {@link PromptInfo#setAuthenticators(int)}, as the former is not flexible enough.
@@ -375,6 +411,15 @@ public class Utils {
return false;
}
+ /** Same as checkPermission but also allows shell. */
+ public static void checkPermissionOrShell(Context context, String permission) {
+ if (Binder.getCallingUid() == Process.SHELL_UID) {
+ return;
+ }
+ checkPermission(context, permission);
+ }
+
+
public static void checkPermission(Context context, String permission) {
context.enforceCallingOrSelfPermission(permission,
"Must have " + permission + " permission.");
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index 5aa9b79c074c..c8a90e7a564b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -92,7 +92,7 @@ public class CoexCoordinator {
void sendHapticFeedback();
}
- private static CoexCoordinator sInstance;
+ private static final CoexCoordinator sInstance = new CoexCoordinator();
@VisibleForTesting
public static class SuccessfulAuth {
@@ -147,14 +147,9 @@ public class CoexCoordinator {
}
}
- /**
- * @return a singleton instance.
- */
+ /** The singleton instance. */
@NonNull
public static CoexCoordinator getInstance() {
- if (sInstance == null) {
- sInstance = new CoexCoordinator();
- }
return sInstance;
}
@@ -339,18 +334,8 @@ public class CoexCoordinator {
auth.mCallback.sendHapticFeedback();
auth.mCallback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
auth.mCallback.handleLifecycleAfterAuth();
- } else if (isFaceScanning()) {
- // UDFPS rejected but face is still scanning
- Slog.d(TAG, "UDFPS rejected in multi-sensor auth, face: " + face);
- callback.handleLifecycleAfterAuth();
-
- // TODO(b/193089985): Enforce/ensure that face auth finishes (whether
- // accept/reject) within X amount of time. Otherwise users will be stuck
- // waiting with their finger down for a long time.
} else {
- // Face not scanning, and was not found in the queue. Most likely, face
- // auth was too long ago.
- Slog.d(TAG, "UDFPS rejected in multi-sensor auth, face not scanning");
+ Slog.d(TAG, "UDFPS rejected in multi-sensor auth");
callback.sendHapticFeedback();
callback.handleLifecycleAfterAuth();
}
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 57ea812dbb3a..ded9c8de4dba 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -19,9 +19,11 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
+import android.os.Build;
import android.os.IBinder;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
@@ -65,6 +67,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
private final List<S> mEnrolledList;
private final boolean mHasEnrollmentsBeforeStarting;
private BaseClientMonitor mCurrentTask;
+ private boolean mFavorHalEnrollments = false;
private final ClientMonitorCallback mEnumerateCallback = new ClientMonitorCallback() {
@Override
@@ -87,7 +90,21 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
// InternalEnumerateClient. Finish this client.
mCallback.onClientFinished(InternalCleanupClient.this, success);
} else {
- startCleanupUnknownHalTemplates();
+ if (mFavorHalEnrollments && Build.isDebuggable()) {
+ // on debug builds, optionally allow the HAL be the source of
+ // truth for enrollments
+ try {
+ for (UserTemplate template : mUnknownHALTemplates) {
+ Slog.i(TAG, "Adding unknown HAL template: "
+ + template.mIdentifier.getBiometricId());
+ onAddUnknownTemplate(template.mUserId, template.mIdentifier);
+ }
+ } finally {
+ mCallback.onClientFinished(InternalCleanupClient.this, success);
+ }
+ } else {
+ startCleanupUnknownHalTemplates();
+ }
}
}
};
@@ -197,8 +214,27 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
((EnumerateConsumer) mCurrentTask).onEnumerationResult(identifier, remaining);
}
+ /** When set unknown templates in the HAL will be added instead of deleted. */
+ public void setFavorHalEnrollments() {
+ mFavorHalEnrollments = true;
+ }
+
+ /** Called when an unknown template is found and setFavorHalEnrollments was requested. */
+ protected void onAddUnknownTemplate(int userId,
+ @NonNull BiometricAuthenticator.Identifier identifier) {}
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_INTERNAL_CLEANUP;
}
+
+ @VisibleForTesting
+ public InternalEnumerateClient<T> getCurrentEnumerateClient() {
+ return (InternalEnumerateClient<T>) mCurrentTask;
+ }
+
+ @VisibleForTesting
+ public RemovalClient<S, T> getCurrentRemoveClient() {
+ return (RemovalClient<S, T>) mCurrentTask;
+ }
}
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 e0d519469e32..45ffa23dc66a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -50,8 +50,6 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
logger, biometricContext);
- //, BiometricsProtoEnums.ACTION_REMOVE,
- // BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
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 2e820574b435..75d09f205192 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
@@ -18,11 +18,13 @@ package com.android.server.biometrics.sensors.face;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
+import static android.Manifest.permission.MANAGE_FACE;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -45,7 +47,9 @@ import android.os.IBinder;
import android.os.NativeHandle;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
@@ -445,6 +449,15 @@ public class FaceService extends SystemService {
}
@Override // Binder call
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err, @NonNull String[] args,
+ @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver)
+ throws RemoteException {
+ (new FaceShellCommand(FaceService.this))
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override // Binder call
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
@@ -732,4 +745,19 @@ public class FaceService extends SystemService {
* @param handle a handle that was obtained from {@link #acquireSurfaceHandle(Surface)}.
*/
public static native void releaseSurfaceHandle(@NonNull NativeHandle handle);
+
+
+ void syncEnrollmentsNow() {
+ Utils.checkPermissionOrShell(getContext(), MANAGE_FACE);
+ if (Utils.isVirtualEnabled(getContext())) {
+ Slog.i(TAG, "Sync virtual enrollments");
+ final int userId = ActivityManager.getCurrentUser();
+ for (ServiceProvider provider : mServiceProviders) {
+ for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
+ provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
+ true /* favorHalEnrollments */);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java
new file mode 100644
index 000000000000..187575dcd664
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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.face;
+
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Handles shell commands for {@link FaceService}. */
+public class FaceShellCommand extends ShellCommand {
+
+ private final FaceService mService;
+
+ public FaceShellCommand(FaceService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ onHelp();
+ return 1;
+ }
+
+ try {
+ switch (cmd) {
+ case "help":
+ return doHelp();
+ case "sync":
+ return doSync();
+ default:
+ getOutPrintWriter().println("Unrecognized command: " + cmd);
+ }
+ } catch (Exception e) {
+ getOutPrintWriter().println("Exception: " + e);
+ }
+ return -1;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Face Service commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" sync");
+ pw.println(" Sync enrollments now (virtualized sensors only).");
+ }
+
+ private int doHelp() {
+ onHelp();
+ return 0;
+ }
+
+ private int doSync() {
+ mService.syncEnrollmentsNow();
+ return 0;
+ }
+}
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 1e9b72b6f4d5..6f98365332e2 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
@@ -139,6 +139,9 @@ public interface ServiceProvider {
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback);
+ void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
+
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
index 54f2033b363a..b0b23faa9aa5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.face.IFace;
import android.hardware.face.Face;
import android.os.IBinder;
@@ -28,6 +29,7 @@ import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.InternalCleanupClient;
import com.android.server.biometrics.sensors.InternalEnumerateClient;
import com.android.server.biometrics.sensors.RemovalClient;
+import com.android.server.biometrics.sensors.face.FaceUtils;
import java.util.List;
import java.util.Map;
@@ -68,4 +70,11 @@ class FaceInternalCleanupClient extends InternalCleanupClient<Face, AidlSession>
null /* ClientMonitorCallbackConverter */, new int[] {biometricId}, userId, owner,
utils, sensorId, logger, biometricContext, authenticatorIds);
}
+
+ @Override
+ protected void onAddUnknownTemplate(int userId,
+ @NonNull BiometricAuthenticator.Identifier identifier) {
+ FaceUtils.getInstance(getSensorId()).addBiometricForUser(
+ getContext(), getTargetUserId(), (Face) identifier);
+ }
}
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 e0900b9df200..19d54c84c706 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
@@ -540,6 +540,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback) {
+ scheduleInternalCleanup(sensorId, userId, callback, false /* favorHalEnrollments */);
+ }
+
+ @Override
+ public void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) {
mHandler.post(() -> {
final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
final FaceInternalCleanupClient client =
@@ -551,6 +557,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mBiometricContext, enrolledList,
FaceUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
+ if (favorHalEnrollments) {
+ client.setFavorHalEnrollments();
+ }
scheduleForSensor(sensorId, client, callback);
});
}
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 73c759f7738c..65289122747c 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
@@ -812,6 +812,12 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
}
@Override
+ public void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) {
+ scheduleInternalCleanup(userId, callback);
+ }
+
+ @Override
public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> {
mScheduler.startPreparedClient(cookie);
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 a26535fbdce3..3d8e4662d314 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
@@ -32,6 +32,7 @@ import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -47,7 +48,6 @@ import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -67,7 +67,9 @@ import android.os.Looper;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -78,6 +80,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
@@ -92,12 +95,16 @@ import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvide
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock;
+import com.google.android.collect.Lists;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Function;
+import java.util.function.Supplier;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -113,10 +120,12 @@ public class FingerprintService extends SystemService {
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
- private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Handler mHandler;
+ @NonNull private final BiometricContext mBiometricContext;
+ @NonNull private final Supplier<IBiometricService> mBiometricServiceSupplier;
+ @NonNull private final Function<String, IFingerprint> mIFingerprintProvider;
@GuardedBy("mLock")
@NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
@@ -167,7 +176,7 @@ public class FingerprintService extends SystemService {
/**
* Receives the incoming binder calls from FingerprintManager.
*/
- private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ private final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
@@ -624,6 +633,15 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err, @NonNull String[] args,
+ @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver)
+ throws RemoteException {
+ (new FingerprintShellCommand(getContext(), FingerprintService.this))
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override // Binder call
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
@@ -841,54 +859,6 @@ public class FingerprintService extends SystemService {
mGestureAvailabilityDispatcher.removeCallback(callback);
}
- private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
- for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
- final Fingerprint21 fingerprint21;
- if ((Build.IS_USERDEBUG || Build.IS_ENG)
- && getContext().getResources().getBoolean(R.bool.allow_test_udfps)
- && Settings.Secure.getIntForUser(getContext().getContentResolver(),
- Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
- UserHandle.USER_CURRENT) != 0) {
- fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
- BiometricContext.getInstance(getContext()));
- } else {
- fingerprint21 = Fingerprint21.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor, mHandler,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
- }
- mServiceProviders.add(fingerprint21);
- }
- }
-
- private void addAidlProviders() {
- final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
- if (instances == null || instances.length == 0) {
- return;
- }
- for (String instance : instances) {
- final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
- final IFingerprint fp = IFingerprint.Stub.asInterface(
- Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));
- if (fp == null) {
- Slog.e(TAG, "Unable to get declared service: " + fqName);
- continue;
- }
- try {
- final SensorProps[] props = fp.getSensorProps();
- final FingerprintProvider provider =
- new FingerprintProvider(getContext(), mBiometricStateCallback, props,
- instance, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher,
- BiometricContext.getInstance(getContext()));
- mServiceProviders.add(provider);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
- }
- }
- }
-
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
@@ -902,42 +872,16 @@ public class FingerprintService extends SystemService {
true /* allowIo */);
thread.start();
final Handler handler = new Handler(thread.getLooper());
-
handler.post(() -> {
- addHidlProviders(hidlSensors);
- addAidlProviders();
-
- final IBiometricService biometricService = IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE));
-
- // Register each sensor individually with BiometricService
- for (ServiceProvider provider : mServiceProviders) {
- final List<FingerprintSensorPropertiesInternal> props =
- provider.getSensorProperties();
- for (FingerprintSensorPropertiesInternal prop : props) {
- final int sensorId = prop.sensorId;
- final @BiometricManager.Authenticators.Types int strength =
- Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
- final FingerprintAuthenticator authenticator = new FingerprintAuthenticator(
- mServiceWrapper, sensorId);
- try {
- biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT,
- strength, authenticator);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
- }
- }
- }
-
- synchronized (mLock) {
- for (ServiceProvider provider : mServiceProviders) {
- mSensorProps.addAll(provider.getSensorProperties());
- }
+ List<String> aidlSensors = new ArrayList<>();
+ final String[] instances =
+ ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
+ if (instances != null) {
+ aidlSensors.addAll(Lists.newArrayList(instances));
}
-
- broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
- broadcastAllAuthenticatorsRegistered();
+ registerAuthenticatorsForService(aidlSensors, hidlSensors);
});
+ thread.quitSafely();
}
@Override
@@ -1021,11 +965,25 @@ public class FingerprintService extends SystemService {
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
FingerprintService.this.registerBiometricStateListener(listener);
}
- }
+ };
public FingerprintService(Context context) {
+ this(context, BiometricContext.getInstance(context),
+ () -> IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
+ (fqName) -> IFingerprint.Stub.asInterface(
+ Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))));
+ }
+
+ @VisibleForTesting
+ FingerprintService(Context context,
+ BiometricContext biometricContext,
+ Supplier<IBiometricService> biometricServiceProvider,
+ Function<String, IFingerprint> fingerprintProvider) {
super(context);
- mServiceWrapper = new FingerprintServiceWrapper();
+ mBiometricContext = biometricContext;
+ mBiometricServiceSupplier = biometricServiceProvider;
+ mIFingerprintProvider = fingerprintProvider;
mAppOps = context.getSystemService(AppOpsManager.class);
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
@@ -1037,6 +995,86 @@ public class FingerprintService extends SystemService {
mHandler = new Handler(Looper.getMainLooper());
}
+ @VisibleForTesting
+ void registerAuthenticatorsForService(@NonNull List<String> aidlInstanceNames,
+ @NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
+ addHidlProviders(hidlSensors);
+ addAidlProviders(Utils.filterAvailableHalInstances(getContext(), aidlInstanceNames));
+
+ final IBiometricService biometricService = mBiometricServiceSupplier.get();
+
+ // Register each sensor individually with BiometricService
+ for (ServiceProvider provider : mServiceProviders) {
+ final List<FingerprintSensorPropertiesInternal> props =
+ provider.getSensorProperties();
+ for (FingerprintSensorPropertiesInternal prop : props) {
+ final int sensorId = prop.sensorId;
+ @BiometricManager.Authenticators.Types final int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
+ final FingerprintAuthenticator authenticator = new FingerprintAuthenticator(
+ mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT,
+ strength, authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
+ }
+
+ synchronized (mLock) {
+ for (ServiceProvider provider : mServiceProviders) {
+ mSensorProps.addAll(provider.getSensorProperties());
+ }
+ }
+
+ broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
+ broadcastAllAuthenticatorsRegistered();
+ }
+
+ private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
+ for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
+ final Fingerprint21 fingerprint21;
+ if ((Build.IS_USERDEBUG || Build.IS_ENG)
+ && getContext().getResources().getBoolean(R.bool.allow_test_udfps)
+ && Settings.Secure.getIntForUser(getContext().getContentResolver(),
+ Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
+ UserHandle.USER_CURRENT) != 0) {
+ fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
+ mBiometricStateCallback, hidlSensor,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
+ BiometricContext.getInstance(getContext()));
+ } else {
+ fingerprint21 = Fingerprint21.newInstance(getContext(),
+ mBiometricStateCallback, hidlSensor, mHandler,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ }
+ mServiceProviders.add(fingerprint21);
+ }
+ }
+
+ private void addAidlProviders(List<String> instances) {
+ for (String instance : instances) {
+ final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
+ final IFingerprint fp = mIFingerprintProvider.apply(fqName);
+
+ if (fp != null) {
+ try {
+ final FingerprintProvider provider = new FingerprintProvider(getContext(),
+ mBiometricStateCallback, fp.getSensorProps(), instance,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
+ mBiometricContext);
+ Slog.i(TAG, "Adding AIDL provider: " + fqName);
+ mServiceProviders.add(provider);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
+ }
+ } else {
+ Slog.e(TAG, "Unable to get declared service: " + fqName);
+ }
+ }
+ }
+
// Notifies the callbacks that all of the authenticators have been registered and removes the
// invoked callbacks from the callback list.
private void broadcastAllAuthenticatorsRegistered() {
@@ -1175,4 +1213,18 @@ public class FingerprintService extends SystemService {
}
return appOpsOk;
}
+
+ void syncEnrollmentsNow() {
+ Utils.checkPermissionOrShell(getContext(), MANAGE_FINGERPRINT);
+ if (Utils.isVirtualEnabled(getContext())) {
+ Slog.i(TAG, "Sync virtual enrollments");
+ final int userId = ActivityManager.getCurrentUser();
+ for (ServiceProvider provider : mServiceProviders) {
+ for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) {
+ provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
+ true /* favorHalEnrollments */);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
new file mode 100644
index 000000000000..636413f75cf5
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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 android.content.Context;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Handles shell commands for {@link FingerprintService}. */
+public class FingerprintShellCommand extends ShellCommand {
+
+ private final Context mContext;
+ private final FingerprintService mService;
+
+ public FingerprintShellCommand(Context context, FingerprintService service) {
+ mContext = context;
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ onHelp();
+ return 1;
+ }
+
+ try {
+ switch (cmd) {
+ case "help":
+ return doHelp();
+ case "sync":
+ return doSync();
+ default:
+ getOutPrintWriter().println("Unrecognized command: " + cmd);
+ }
+ } catch (Exception e) {
+ getOutPrintWriter().println("Exception: " + e);
+ }
+ return -1;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Fingerprint Service commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" sync");
+ pw.println(" Sync enrollments now (virtualized sensors only).");
+ }
+
+ private int doHelp() {
+ onHelp();
+ return 0;
+ }
+
+ private int doSync() {
+ mService.syncEnrollmentsNow();
+ return 0;
+ }
+}
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 9cdbdc9158fb..4dfc73872014 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
@@ -123,6 +123,9 @@ public interface ServiceProvider {
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback);
+ void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
+
boolean isHardwareDetected(int sensorId);
void rename(int sensorId, int fingerId, int userId, @NonNull String name);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
index 09bdd6de49f0..c315ccf8dea2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.fingerprint.Fingerprint;
import android.os.IBinder;
@@ -72,4 +73,11 @@ class FingerprintInternalCleanupClient extends InternalCleanupClient<Fingerprint
utils, sensorId, logger.swapAction(context, BiometricsProtoEnums.ACTION_REMOVE),
biometricContext, authenticatorIds);
}
+
+ @Override
+ protected void onAddUnknownTemplate(int userId,
+ @NonNull BiometricAuthenticator.Identifier identifier) {
+ FingerprintUtils.getInstance(getSensorId()).addBiometricForUser(
+ getContext(), getTargetUserId(), (Fingerprint) identifier);
+ }
}
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 f16af78364a2..668f4c460879 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
@@ -511,6 +511,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback) {
+ scheduleInternalCleanup(sensorId, userId, callback, false /* favorHalEnrollments */);
+ }
+
+ @Override
+ public void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) {
mHandler.post(() -> {
final List<Fingerprint> enrolledList = getEnrolledFingerprints(sensorId, userId);
final FingerprintInternalCleanupClient client =
@@ -522,6 +528,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext,
enrolledList, FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
+ if (favorHalEnrollments) {
+ client.setFavorHalEnrollments();
+ }
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(callback,
mBiometricStateCallback));
});
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 2a3f34ae3cd4..0c7bcc78d8ef 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
@@ -752,6 +752,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricStateCallback));
}
+ @Override
+ public void scheduleInternalCleanup(int sensorId, int userId,
+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) {
+ scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback,
+ mBiometricStateCallback));
+ }
+
private BiometricLogger createLogger(int statsAction, int statsClient) {
return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FINGERPRINT,
statsAction, statsClient);
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index aab6281e6cd1..387e00f73932 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -20,9 +20,9 @@ import static android.Manifest.permission.LOG_COMPAT_CHANGE;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Process.SYSTEM_UID;
+import android.annotation.EnforcePermission;
+import android.annotation.RequiresNoPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
@@ -93,15 +93,15 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(LOG_COMPAT_CHANGE)
public void reportChange(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeLogPermission();
reportChangeInternal(changeId, appInfo.uid, ChangeReporter.STATE_LOGGED);
}
@Override
+ @EnforcePermission(LOG_COMPAT_CHANGE)
public void reportChangeByPackageName(long changeId, String packageName,
@UserIdInt int userId) {
- checkCompatChangeLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo != null) {
reportChangeInternal(changeId, appInfo.uid, ChangeReporter.STATE_LOGGED);
@@ -109,8 +109,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(LOG_COMPAT_CHANGE)
public void reportChangeByUid(long changeId, int uid) {
- checkCompatChangeLogPermission();
reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED);
}
@@ -119,15 +119,15 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeReadAndLogPermission();
return isChangeEnabledInternal(changeId, appInfo);
}
@Override
+ @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
public boolean isChangeEnabledByPackageName(long changeId, String packageName,
@UserIdInt int userId) {
- checkCompatChangeReadAndLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return mCompatConfig.willChangeBeEnabled(changeId, packageName);
@@ -136,8 +136,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
public boolean isChangeEnabledByUid(long changeId, int uid) {
- checkCompatChangeReadAndLogPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
return mCompatConfig.defaultChangeIdValue(changeId);
@@ -197,8 +197,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
- checkCompatChangeOverridePermission();
Map<Long, PackageOverride> overridesMap = new HashMap<>();
for (long change : overrides.enabledChanges()) {
overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
@@ -213,8 +213,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
- checkCompatChangeOverridePermission();
Map<Long, PackageOverride> overridesMap = new HashMap<>();
for (long change : overrides.enabledChanges()) {
overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
@@ -228,9 +228,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
public void putAllOverridesOnReleaseBuilds(
CompatibilityOverridesByPackageConfig overridesByPackage) {
- checkCompatChangeOverrideOverridablePermission();
for (CompatibilityOverrideConfig overrides :
overridesByPackage.packageNameToOverrides.values()) {
checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
@@ -239,16 +239,16 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
public void putOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
String packageName) {
- checkCompatChangeOverrideOverridablePermission();
checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
mCompatConfig.addPackageOverrides(overrides, packageName, /* skipUnknownChangeIds= */ true);
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public int enableTargetSdkChanges(String packageName, int targetSdkVersion) {
- checkCompatChangeOverridePermission();
int numChanges =
mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion);
killPackage(packageName);
@@ -256,8 +256,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public int disableTargetSdkChanges(String packageName, int targetSdkVersion) {
- checkCompatChangeOverridePermission();
int numChanges =
mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion);
killPackage(packageName);
@@ -265,36 +265,36 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public void clearOverrides(String packageName) {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public void clearOverridesForTest(String packageName) {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public boolean clearOverride(long changeId, String packageName) {
- checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
public boolean clearOverrideForTest(long changeId, String packageName) {
- checkCompatChangeOverridePermission();
return mCompatConfig.removeOverride(changeId, packageName);
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
public void removeAllOverridesOnReleaseBuilds(
CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
- checkCompatChangeOverrideOverridablePermission();
for (CompatibilityOverridesToRemoveConfig overridesToRemove :
overridesToRemoveByPackage.packageNameToOverridesToRemove.values()) {
checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
@@ -303,27 +303,28 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ @EnforcePermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
public void removeOverridesOnReleaseBuilds(
CompatibilityOverridesToRemoveConfig overridesToRemove,
String packageName) {
- checkCompatChangeOverrideOverridablePermission();
checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
mCompatConfig.removePackageOverrides(overridesToRemove, packageName);
}
@Override
+ @EnforcePermission(allOf = {LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG})
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- checkCompatChangeReadAndLogPermission();
return mCompatConfig.getAppConfig(appInfo);
}
@Override
+ @EnforcePermission(READ_COMPAT_CHANGE_CONFIG)
public CompatibilityChangeInfo[] listAllChanges() {
- checkCompatChangeReadPermission();
return mCompatConfig.dumpChanges();
}
@Override
+ @RequiresNoPermission
public CompatibilityChangeInfo[] listUIChanges() {
return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray(
CompatibilityChangeInfo[]::new);
@@ -362,11 +363,15 @@ public class PlatformCompat extends IPlatformCompat.Stub {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) {
return;
}
- checkCompatChangeReadAndLogPermission();
+ mContext.enforceCallingOrSelfPermission(
+ READ_COMPAT_CHANGE_CONFIG, "Cannot read compat change");
+ mContext.enforceCallingOrSelfPermission(
+ LOG_COMPAT_CHANGE, "Cannot read log compat change usage");
mCompatConfig.dumpConfig(pw);
}
@Override
+ @RequiresNoPermission
public IOverrideValidator getOverrideValidator() {
return mCompatConfig.getOverrideValidator();
}
@@ -414,49 +419,6 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
}
- private void checkCompatChangeLogPermission() throws SecurityException {
- // Don't check for permissions within the system process
- if (Binder.getCallingUid() == SYSTEM_UID) {
- return;
- }
- if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot log compat change usage");
- }
- }
-
- private void checkCompatChangeReadPermission() {
- // Don't check for permissions within the system process
- if (Binder.getCallingUid() == SYSTEM_UID) {
- return;
- }
- if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot read compat change");
- }
- }
-
- private void checkCompatChangeOverridePermission() {
- // Don't check for permissions within the system process
- if (Binder.getCallingUid() == SYSTEM_UID) {
- return;
- }
- if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot override compat change");
- }
- }
-
- private void checkCompatChangeOverrideOverridablePermission() {
- // Don't check for permissions within the system process
- if (Binder.getCallingUid() == SYSTEM_UID) {
- return;
- }
- if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot override compat change");
- }
- }
-
private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) {
for (Long changeId : changeIds) {
if (isKnownChangeId(changeId) && !mCompatConfig.isOverridable(changeId)) {
@@ -466,11 +428,6 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
}
- private void checkCompatChangeReadAndLogPermission() {
- checkCompatChangeReadPermission();
- checkCompatChangeLogPermission();
- }
-
private boolean isShownInUI(CompatibilityChangeInfo change) {
if (change.getLoggingOnly()) {
return false;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 254a3226e6de..6920ec6a30a7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -86,9 +86,14 @@ import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
+import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.ipsec.ike.exceptions.IkeTimeoutException;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -165,9 +170,10 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -760,31 +766,36 @@ public class Vpn {
// Also notify the new package if there was a provider change.
final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
- if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
- saveAlwaysOnPackage();
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyOldPkg && SdkLevel.isAtLeastT()) {
- // If both of shouldNotifyOldPkg & isPackageChanged are true, which means the
- // always-on of old package is disabled or the old package is replaced with the new
- // package. In this case, VpnProfileState should be disconnected.
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
- null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
- : makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyNewPkg && SdkLevel.isAtLeastT()) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, packageName,
- getSessionKeyLocked(), makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
+ if (!setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
+ return false;
+ }
+
+ saveAlwaysOnPackage();
+
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (!SdkLevel.isAtLeastT()) {
return true;
}
- return false;
+
+ if (shouldNotifyOldPkg) {
+ // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the
+ // always-on of old package is disabled or the old package is replaced with the new
+ // package. In this case, VpnProfileState should be disconnected.
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
+ null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
+ : makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+
+ if (shouldNotifyNewPkg) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+ return true;
}
/**
@@ -1626,7 +1637,9 @@ public class Vpn {
for (String app : packageNames) {
int uid = getAppUid(app, userId);
if (uid != -1) uids.add(uid);
- if (Process.isApplicationUid(uid)) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) {
uids.add(Process.toSdkSandboxUid(uid));
}
}
@@ -2530,6 +2543,21 @@ public class Vpn {
}
}
+ @Nullable
+ protected synchronized NetworkCapabilities getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ NetworkCapabilities nc) {
+ if (nc == null) return null;
+ return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage(
+ nc, mOwnerUID, mPackage);
+ }
+
+ @Nullable
+ protected synchronized LinkProperties getRedactedLinkPropertiesOfUnderlyingNetwork(
+ LinkProperties lp) {
+ if (lp == null) return null;
+ return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage);
+ }
+
/** This class represents the common interface for all VPN runners. */
@VisibleForTesting
abstract class VpnRunner extends Thread {
@@ -2564,13 +2592,27 @@ public class Vpn {
interface IkeV2VpnRunnerCallback {
void onDefaultNetworkChanged(@NonNull Network network);
- void onChildOpened(
- @NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
+ void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc);
+
+ void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
+
+ void onDefaultNetworkLost(@NonNull Network network);
+
+ void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration);
- void onChildTransformCreated(
- @NonNull Network network, @NonNull IpSecTransform transform, int direction);
+ void onIkeConnectionInfoChanged(
+ int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo);
- void onSessionLost(@NonNull Network network, @Nullable Exception exception);
+ void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig);
+
+ void onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction);
+
+ void onChildMigrated(
+ int token,
+ @NonNull IpSecTransform inTransform,
+ @NonNull IpSecTransform outTransform);
+
+ void onSessionLost(int token, @Nullable Exception exception);
}
/**
@@ -2601,6 +2643,10 @@ public class Vpn {
class IkeV2VpnRunner extends VpnRunner implements IkeV2VpnRunnerCallback {
@NonNull private static final String TAG = "IkeV2VpnRunner";
+ // 5 seconds grace period before tearing down the IKE Session in case new default network
+ // will come up
+ private static final long NETWORK_LOST_TIMEOUT_MS = 5000L;
+
@NonNull private final IpSecManager mIpSecManager;
@NonNull private final Ikev2VpnProfile mProfile;
@NonNull private final ConnectivityManager.NetworkCallback mNetworkCallback;
@@ -2612,24 +2658,51 @@ public class Vpn {
* of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by
* virtue of everything being serialized on this executor.
*/
- @NonNull private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ @NonNull
+ private final ScheduledThreadPoolExecutor mExecutor = new ScheduledThreadPoolExecutor(1);
+
+ @Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostTimeout;
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
+ /**
+ * The token used by the primary/current/active IKE session.
+ *
+ * <p>This token MUST be updated when the VPN switches to use a new IKE session.
+ */
+ private int mCurrentToken = -1;
+
@Nullable private IpSecTunnelInterface mTunnelIface;
- @Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
+ @Nullable private NetworkCapabilities mUnderlyingNetworkCapabilities;
+ @Nullable private LinkProperties mUnderlyingLinkProperties;
private final String mSessionKey;
+ @Nullable private IkeSession mSession;
+ @Nullable private IkeSessionConnectionInfo mIkeConnectionInfo;
+
+ // mMobikeEnabled can only be updated after IKE AUTH is finished.
+ private boolean mMobikeEnabled = false;
+
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
super(TAG);
mProfile = profile;
mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- // Pass mExecutor into Ikev2VpnNetworkCallback and make sure that IkeV2VpnRunnerCallback
- // will be called by the mExecutor thread.
mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor);
mSessionKey = UUID.randomUUID().toString();
+
+ // Set the policy so that cancelled tasks will be removed from the work queue
+ mExecutor.setRemoveOnCancelPolicy(true);
+
+ // Set the policy so that all delayed tasks will not be executed
+ mExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+
+ // To avoid hitting RejectedExecutionException upon shutdown of the mExecutor */
+ mExecutor.setRejectedExecutionHandler(
+ (r, executor) -> {
+ Log.d(TAG, "Runnable " + r + " rejected by the mExecutor");
+ });
}
@Override
@@ -2668,22 +2741,63 @@ public class Vpn {
return Objects.equals(mActiveNetwork, network) && mIsRunning;
}
+ private boolean isActiveToken(int token) {
+ return (mCurrentToken == token) && mIsRunning;
+ }
+
+ /**
+ * Called when an IKE session has been opened
+ *
+ * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
+ * thread in order to ensure consistency of the Ikev2VpnRunner fields.
+ */
+ public void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onIkeOpened called for obsolete token " + token);
+ return;
+ }
+
+ mMobikeEnabled =
+ ikeConfiguration.isIkeExtensionEnabled(
+ IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE);
+ onIkeConnectionInfoChanged(token, ikeConfiguration.getIkeSessionConnectionInfo());
+ }
+
+ /**
+ * Called when an IKE session's {@link IkeSessionConnectionInfo} is available or updated
+ *
+ * <p>This callback is usually fired when an IKE session has been opened or migrated.
+ *
+ * <p>This method is called multiple times over the lifetime of an IkeSession, and MUST run
+ * on the mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields.
+ */
+ public void onIkeConnectionInfoChanged(
+ int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onIkeConnectionInfoChanged called for obsolete token " + token);
+ return;
+ }
+
+ // The update on VPN and the IPsec tunnel will be done when migration is fully complete
+ // in onChildMigrated
+ mIkeConnectionInfo = ikeConnectionInfo;
+ }
+
/**
* Called when an IKE Child session has been opened, signalling completion of the startup.
*
* <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
* thread in order to ensure consistency of the Ikev2VpnRunner fields.
*/
- public void onChildOpened(
- @NonNull Network network, @NonNull ChildSessionConfiguration childConfig) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "onOpened called for obsolete network " + network);
+ public void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onChildOpened called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
@@ -2702,6 +2816,11 @@ public class Vpn {
dnsAddrStrings.add(addr.getHostAddress());
}
+ // The actual network of this IKE session has been set up with is
+ // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because
+ // mActiveNetwork might have been updated after the setup was triggered.
+ final Network network = mIkeConnectionInfo.getNetwork();
+
final NetworkAgent networkAgent;
final LinkProperties lp;
@@ -2744,8 +2863,8 @@ public class Vpn {
networkAgent.sendLinkProperties(lp);
} catch (Exception e) {
- Log.d(TAG, "Error in ChildOpened for network " + network, e);
- onSessionLost(network, e);
+ Log.d(TAG, "Error in ChildOpened for token " + token, e);
+ onSessionLost(token, e);
}
}
@@ -2753,19 +2872,19 @@ public class Vpn {
* Called when an IPsec transform has been created, and should be applied.
*
* <p>This method is called multiple times over the lifetime of an IkeSession (or default
- * network), and is MUST always be called on the mExecutor thread in order to ensure
+ * network), and MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
public void onChildTransformCreated(
- @NonNull Network network, @NonNull IpSecTransform transform, int direction) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "ChildTransformCreated for obsolete network " + network);
+ int token, @NonNull IpSecTransform transform, int direction) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "ChildTransformCreated for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
@@ -2774,22 +2893,71 @@ public class Vpn {
// them alive for us
mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
} catch (IOException e) {
- Log.d(TAG, "Transform application failed for network " + network, e);
- onSessionLost(network, e);
+ Log.d(TAG, "Transform application failed for token " + token, e);
+ onSessionLost(token, e);
+ }
+ }
+
+ /**
+ * Called when an IPsec transform has been created, and should be re-applied.
+ *
+ * <p>This method is called multiple times over the lifetime of an IkeSession (or default
+ * network), and MUST always be called on the mExecutor thread in order to ensure
+ * consistency of the Ikev2VpnRunner fields.
+ */
+ public void onChildMigrated(
+ int token,
+ @NonNull IpSecTransform inTransform,
+ @NonNull IpSecTransform outTransform) {
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onChildMigrated for obsolete token " + token);
+ return;
+ }
+
+ // The actual network of this IKE session has migrated to is
+ // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because mActiveNetwork
+ // might have been updated after the migration was triggered.
+ final Network network = mIkeConnectionInfo.getNetwork();
+
+ try {
+ synchronized (Vpn.this) {
+ mConfig.underlyingNetworks = new Network[] {network};
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUnderlyingNetworks(Collections.singletonList(network))
+ .build();
+ mNetworkAgent.setUnderlyingNetworks(Collections.singletonList(network));
+ }
+
+ mTunnelIface.setUnderlyingNetwork(network);
+
+ // Transforms do not need to be persisted; the IkeSession will keep them alive for
+ // us
+ mIpSecManager.applyTunnelModeTransform(
+ mTunnelIface, IpSecManager.DIRECTION_IN, inTransform);
+ mIpSecManager.applyTunnelModeTransform(
+ mTunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
+ } catch (IOException e) {
+ Log.d(TAG, "Transform application failed for token " + token, e);
+ onSessionLost(token, e);
}
}
/**
* Called when a new default network is connected.
*
- * <p>The Ikev2VpnRunner will unconditionally switch to the new network, killing the old IKE
- * state in the process, and starting a new IkeSession instance.
+ * <p>The Ikev2VpnRunner will unconditionally switch to the new network. If the IKE session
+ * has mobility, Ikev2VpnRunner will migrate the existing IkeSession to the new network.
+ * Otherwise, Ikev2VpnRunner will kill the old IKE state, and start a new IkeSession
+ * instance.
*
* <p>This method MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
public void onDefaultNetworkChanged(@NonNull Network network) {
- Log.d(TAG, "Starting IKEv2/IPsec session on new network: " + network);
+ Log.d(TAG, "onDefaultNetworkChanged: " + network);
+
+ cancelHandleNetworkLostTimeout();
try {
if (!mIsRunning) {
@@ -2797,13 +2965,27 @@ public class Vpn {
return; // VPN has been shut down.
}
+ mActiveNetwork = network;
+
+ if (mSession != null && mMobikeEnabled) {
+ // IKE session can schedule a migration event only when IKE AUTH is finished
+ // and mMobikeEnabled is true.
+ Log.d(
+ TAG,
+ "Migrate IKE Session with token "
+ + mCurrentToken
+ + " to network "
+ + network);
+ mSession.setNetwork(network);
+ return;
+ }
+
// Clear mInterface to prevent Ikev2VpnRunner being cleared when
// interfaceRemoved() is called.
mInterface = null;
// Without MOBIKE, we have no way to seamlessly migrate. Close on old
// (non-default) network, and start the new one.
resetIkeState();
- mActiveNetwork = network;
// Get Ike options from IkeTunnelConnectionParams if it's available in the
// profile.
@@ -2826,26 +3008,113 @@ public class Vpn {
// TODO: Remove the need for adding two unused addresses with
// IPsec tunnels.
final InetAddress address = InetAddress.getLocalHost();
+
+ // When onChildOpened is called and transforms are applied, it is
+ // guaranteed that the underlying network is still "network", because the
+ // all the network switch events will be deferred before onChildOpened is
+ // called. Thus it is safe to build a mTunnelIface before IKE setup.
mTunnelIface =
mIpSecManager.createIpSecTunnelInterface(
- address /* unused */,
- address /* unused */,
- network);
+ address /* unused */, address /* unused */, network);
NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
- mSession = mIkev2SessionCreator.createIkeSession(
- mContext,
- ikeSessionParams,
- childSessionParams,
- mExecutor,
- new VpnIkev2Utils.IkeSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network),
- new VpnIkev2Utils.ChildSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network));
- Log.d(TAG, "Ike Session started for network " + network);
+ final int token = ++mCurrentToken;
+ mSession =
+ mIkev2SessionCreator.createIkeSession(
+ mContext,
+ ikeSessionParams,
+ childSessionParams,
+ mExecutor,
+ new VpnIkev2Utils.IkeSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, token),
+ new VpnIkev2Utils.ChildSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, token));
+ Log.d(TAG, "IKE session started for token " + token);
} catch (Exception e) {
- Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
- onSessionLost(network, e);
+ Log.i(TAG, "Setup failed for token " + mCurrentToken + ". Aborting", e);
+ onSessionLost(mCurrentToken, e);
+ }
+ }
+
+ /** Called when the NetworkCapabilities of underlying network is changed */
+ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) {
+ mUnderlyingNetworkCapabilities = nc;
+ }
+
+ /** Called when the LinkProperties of underlying network is changed */
+ public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
+ mUnderlyingLinkProperties = lp;
+ }
+
+ /**
+ * Handles loss of the default underlying network
+ *
+ * <p>If the IKE Session has mobility, Ikev2VpnRunner will schedule a teardown event with a
+ * delay so that the IKE Session can migrate if a new network is available soon. Otherwise,
+ * Ikev2VpnRunner will kill the IKE session and reset the VPN.
+ *
+ * <p>This method MUST always be called on the mExecutor thread in order to ensure
+ * consistency of the Ikev2VpnRunner fields.
+ */
+ public void onDefaultNetworkLost(@NonNull Network network) {
+ if (!isActiveNetwork(network)) {
+ Log.d(TAG, "onDefaultNetworkLost called for obsolete network " + network);
+
+ // Do nothing; this signals that either: (1) a new/better Network was found,
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
+ return;
+ }
+
+ if (mScheduledHandleNetworkLostTimeout != null
+ && !mScheduledHandleNetworkLostTimeout.isCancelled()
+ && !mScheduledHandleNetworkLostTimeout.isDone()) {
+ final IllegalStateException exception =
+ new IllegalStateException(
+ "Found a pending mScheduledHandleNetworkLostTimeout");
+ Log.i(
+ TAG,
+ "Unexpected error in onDefaultNetworkLost. Tear down session",
+ exception);
+ handleSessionLost(exception);
+ return;
+ }
+
+ if (mSession != null && mMobikeEnabled) {
+ Log.d(
+ TAG,
+ "IKE Session has mobility. Delay handleSessionLost for losing network "
+ + network
+ + "on session with token "
+ + mCurrentToken);
+
+ // Delay the teardown in case a new network will be available soon. For example,
+ // during handover between two WiFi networks, Android will disconnect from the
+ // first WiFi and then connects to the second WiFi.
+ mScheduledHandleNetworkLostTimeout =
+ mExecutor.schedule(
+ () -> {
+ handleSessionLost(null);
+ },
+ NETWORK_LOST_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ } else {
+ Log.d(TAG, "Call handleSessionLost for losing network " + network);
+ handleSessionLost(null);
+ }
+ }
+
+ private void cancelHandleNetworkLostTimeout() {
+ if (mScheduledHandleNetworkLostTimeout != null
+ && !mScheduledHandleNetworkLostTimeout.isDone()) {
+ // It does not matter what to put in #cancel(boolean), because it is impossible
+ // that the task tracked by mScheduledHandleNetworkLostTimeout is
+ // in-progress since both that task and onDefaultNetworkChanged are submitted to
+ // mExecutor who has only one thread.
+ Log.d(TAG, "Cancel the task for handling network lost timeout");
+ mScheduledHandleNetworkLostTimeout.cancel(false /* mayInterruptIfRunning */);
}
}
@@ -2867,44 +3136,146 @@ public class Vpn {
* <p>This method MUST always be called on the mExecutor thread in order to ensure
* consistency of the Ikev2VpnRunner fields.
*/
- public void onSessionLost(@NonNull Network network, @Nullable Exception exception) {
- if (!isActiveNetwork(network)) {
- Log.d(TAG, "onSessionLost() called for obsolete network " + network);
+ public void onSessionLost(int token, @Nullable Exception exception) {
+ Log.d(TAG, "onSessionLost() called for token " + token);
+
+ if (!isActiveToken(token)) {
+ Log.d(TAG, "onSessionLost() called for obsolete token " + token);
// Do nothing; this signals that either: (1) a new/better Network was found,
- // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
- // IKE session was already shut down (exited, or an error was encountered somewhere
- // else). In both cases, all resources and sessions are torn down via
- // onSessionLost() and resetIkeState().
+ // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
+ // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
+ // or an error was encountered somewhere else). In both cases, all resources and
+ // sessions are torn down via resetIkeState().
return;
}
- if (exception instanceof IkeProtocolException) {
- final IkeProtocolException ikeException = (IkeProtocolException) exception;
+ handleSessionLost(exception);
+ }
- switch (ikeException.getErrorType()) {
- case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
- // All the above failures are configuration errors, and are terminal
- markFailedAndDisconnect(exception);
- return;
- // All other cases possibly recoverable.
+ private void handleSessionLost(@Nullable Exception exception) {
+ // Cancel mScheduledHandleNetworkLostTimeout if the session it is going to terminate is
+ // already terminated due to other failures.
+ cancelHandleNetworkLostTimeout();
+
+ synchronized (Vpn.this) {
+ if (exception instanceof IkeProtocolException) {
+ final IkeProtocolException ikeException = (IkeProtocolException) exception;
+
+ switch (ikeException.getErrorType()) {
+ case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ markFailedAndDisconnect(exception);
+ return;
+ // All other cases possibly recoverable.
+ default:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ }
+ } else if (exception instanceof IllegalArgumentException) {
+ // Failed to build IKE/ChildSessionParams; fatal profile configuration error
+ markFailedAndDisconnect(exception);
+ return;
+ } else if (exception instanceof IkeNetworkLostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_LOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception instanceof IkeNonProtocolException) {
+ if (exception.getCause() instanceof UnknownHostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IkeTimeoutException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IOException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_IO,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ }
+ } else if (exception != null) {
+ Log.wtf(TAG, "onSessionLost: exception = " + exception);
}
- } else if (exception instanceof IllegalArgumentException) {
- // Failed to build IKE/ChildSessionParams; fatal profile configuration error
- markFailedAndDisconnect(exception);
- return;
}
mActiveNetwork = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
// (Mirrors VpnService behavior)
- Log.d(TAG, "Resetting state for network: " + network);
+ Log.d(TAG, "Resetting state for token: " + mCurrentToken);
synchronized (Vpn.this) {
// Since this method handles non-fatal errors only, set mInterface to null to
@@ -2949,6 +3320,8 @@ public class Vpn {
mSession.kill(); // Kill here to make sure all resources are released immediately
mSession = null;
}
+ mIkeConnectionInfo = null;
+ mMobikeEnabled = false;
}
/**
@@ -2965,6 +3338,8 @@ public class Vpn {
*/
private void disconnectVpnRunner() {
mActiveNetwork = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
mIsRunning = false;
resetIkeState();
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 6982d6095689..857c86de57ca 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -50,7 +50,9 @@ import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecAlgorithm;
import android.net.IpSecTransform;
+import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.ChildSaProposal;
@@ -66,6 +68,7 @@ import android.net.ipsec.ike.IkeRfc822AddrIdentification;
import android.net.ipsec.ike.IkeSaProposal;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
@@ -86,7 +89,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executor;
/**
* Utility class to build and convert IKEv2/IPsec parameters.
@@ -105,6 +108,7 @@ public class VpnIkev2Utils {
new IkeSessionParams.Builder(context)
.setServerHostname(profile.getServerAddr())
.setNetwork(network)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
.setLocalIdentification(localId)
.setRemoteIdentification(remoteId);
setIkeAuth(profile, ikeOptionsBuilder);
@@ -296,72 +300,79 @@ public class VpnIkev2Utils {
static class IkeSessionCallbackImpl implements IkeSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final Network mNetwork;
+ private final int mToken;
- IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+ IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
- mNetwork = network;
+ mToken = token;
}
@Override
public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
- Log.d(mTag, "IkeOpened for network " + mNetwork);
- // Nothing to do here.
+ Log.d(mTag, "IkeOpened for token " + mToken);
+ mCallback.onIkeOpened(mToken, ikeSessionConfig);
}
@Override
public void onClosed() {
- Log.d(mTag, "IkeClosed for network " + mNetwork);
- mCallback.onSessionLost(mNetwork, null); // Server requested session closure. Retry?
+ Log.d(mTag, "IkeClosed for token " + mToken);
+ mCallback.onSessionLost(mToken, null); // Server requested session closure. Retry?
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Log.d(mTag, "IkeClosedExceptionally for network " + mNetwork, exception);
- mCallback.onSessionLost(mNetwork, exception);
+ Log.d(mTag, "IkeClosedExceptionally for token " + mToken, exception);
+ mCallback.onSessionLost(mToken, exception);
}
@Override
public void onError(@NonNull IkeProtocolException exception) {
- Log.d(mTag, "IkeError for network " + mNetwork, exception);
+ Log.d(mTag, "IkeError for token " + mToken, exception);
// Non-fatal, log and continue.
}
+
+ @Override
+ public void onIkeSessionConnectionInfoChanged(
+ @NonNull IkeSessionConnectionInfo connectionInfo) {
+ Log.d(mTag, "onIkeSessionConnectionInfoChanged for token " + mToken);
+ mCallback.onIkeConnectionInfoChanged(mToken, connectionInfo);
+ }
}
static class ChildSessionCallbackImpl implements ChildSessionCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final Network mNetwork;
+ private final int mToken;
- ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+ ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) {
mTag = tag;
mCallback = callback;
- mNetwork = network;
+ mToken = token;
}
@Override
public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
- Log.d(mTag, "ChildOpened for network " + mNetwork);
- mCallback.onChildOpened(mNetwork, childConfig);
+ Log.d(mTag, "ChildOpened for token " + mToken);
+ mCallback.onChildOpened(mToken, childConfig);
}
@Override
public void onClosed() {
- Log.d(mTag, "ChildClosed for network " + mNetwork);
- mCallback.onSessionLost(mNetwork, null);
+ Log.d(mTag, "ChildClosed for token " + mToken);
+ mCallback.onSessionLost(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Log.d(mTag, "ChildClosedExceptionally for network " + mNetwork, exception);
- mCallback.onSessionLost(mNetwork, exception);
+ Log.d(mTag, "ChildClosedExceptionally for token " + mToken, exception);
+ mCallback.onSessionLost(mToken, exception);
}
@Override
public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
- Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; network " + mNetwork);
- mCallback.onChildTransformCreated(mNetwork, transform, direction);
+ Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
+ mCallback.onChildTransformCreated(mToken, transform, direction);
}
@Override
@@ -369,18 +380,25 @@ public class VpnIkev2Utils {
// Nothing to be done; no references to the IpSecTransform are held by the
// Ikev2VpnRunner (or this callback class), and this transform will be closed by the
// IKE library.
- Log.d(mTag,
- "ChildTransformDeleted; Direction: " + direction + "; for network " + mNetwork);
+ Log.d(mTag, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
+ }
+
+ @Override
+ public void onIpSecTransformsMigrated(
+ @NonNull IpSecTransform inIpSecTransform,
+ @NonNull IpSecTransform outIpSecTransform) {
+ Log.d(mTag, "ChildTransformsMigrated; token " + mToken);
+ mCallback.onChildMigrated(mToken, inIpSecTransform, outIpSecTransform);
}
}
static class Ikev2VpnNetworkCallback extends NetworkCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final ExecutorService mExecutor;
+ private final Executor mExecutor;
Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback,
- ExecutorService executor) {
+ Executor executor) {
mTag = tag;
mCallback = callback;
mExecutor = executor;
@@ -388,14 +406,30 @@ public class VpnIkev2Utils {
@Override
public void onAvailable(@NonNull Network network) {
- Log.d(mTag, "Starting IKEv2/IPsec session on new network: " + network);
+ Log.d(mTag, "onAvailable called for network: " + network);
mExecutor.execute(() -> mCallback.onDefaultNetworkChanged(network));
}
@Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ Log.d(mTag, "NC changed for net " + network + " : " + networkCapabilities);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkCapabilitiesChanged(networkCapabilities));
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(@NonNull Network network,
+ @NonNull LinkProperties linkProperties) {
+ Log.d(mTag, "LP changed for net " + network + " : " + linkProperties);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkLinkPropertiesChanged(linkProperties));
+ }
+
+ @Override
public void onLost(@NonNull Network network) {
- Log.d(mTag, "Tearing down; lost network: " + network);
- mExecutor.execute(() -> mCallback.onSessionLost(network, null));
+ Log.d(mTag, "onLost called for network: " + network);
+ mExecutor.execute(() -> mCallback.onDefaultNetworkLost(network));
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 2564ae8d8783..75b4eb4de5d6 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -51,7 +51,6 @@ import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.IContentObserver;
-import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.AppBackgroundRestrictionsInfo;
import android.os.Binder;
@@ -209,11 +208,8 @@ public final class ContentService extends IContentService.Stub {
private SyncManager getSyncManager() {
synchronized(mSyncManagerLock) {
- try {
- // Try to create the SyncManager, return null if it fails (which it shouldn't).
- if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
- } catch (SQLiteException e) {
- Log.e(TAG, "Can't create SyncManager", e);
+ if (mSyncManager == null) {
+ mSyncManager = new SyncManager(mContext, mFactoryTest);
}
return mSyncManager;
}
@@ -480,6 +476,7 @@ public final class ContentService extends IContentService.Stub {
// Actually dispatch all the notifications we collected
collector.dispatch();
+ final SyncManager syncManager = getSyncManager();
for (int i = 0; i < validatedProviders.size(); i++) {
final String authority = validatedProviders.keyAt(i).first;
final int resolvedUserId = validatedProviders.keyAt(i).second;
@@ -487,13 +484,10 @@ public final class ContentService extends IContentService.Stub {
// Kick off sync adapters for any authorities we touched
if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.scheduleLocalSync(null /* all accounts */, callingUserId,
- callingUid,
- authority, getSyncExemptionForCaller(callingUid),
- callingUid, callingPid, callingPackage);
- }
+ syncManager.scheduleLocalSync(null /* all accounts */, callingUserId,
+ callingUid,
+ authority, getSyncExemptionForCaller(callingUid),
+ callingUid, callingPid, callingPackage);
}
// Invalidate caches for any authorities we touched
@@ -622,12 +616,9 @@ public final class ContentService extends IContentService.Stub {
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.scheduleSync(account, userId, callingUid, authority, extras,
- SyncStorageEngine.AuthorityInfo.UNDEFINED,
- syncExemption, callingUid, callingPid, callingPackage);
- }
+ getSyncManager().scheduleSync(account, userId, callingUid, authority, extras,
+ SyncStorageEngine.AuthorityInfo.UNDEFINED,
+ syncExemption, callingUid, callingPid, callingPackage);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -679,10 +670,6 @@ public final class ContentService extends IContentService.Stub {
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager == null) {
- return;
- }
long flextime = request.getSyncFlexTime();
long runAtTime = request.getSyncRunTime();
if (request.isPeriodic()) {
@@ -698,7 +685,7 @@ public final class ContentService extends IContentService.Stub {
getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
flextime, extras);
} else {
- syncManager.scheduleSync(
+ getSyncManager().scheduleSync(
request.getAccount(), userId, callingUid, request.getProvider(), extras,
SyncStorageEngine.AuthorityInfo.UNDEFINED,
syncExemption, callingUid, callingPid, callingPackage);
@@ -743,21 +730,20 @@ public final class ContentService extends IContentService.Stub {
}
enforceCrossUserPermission(userId,
"no permission to modify the sync settings for user " + userId);
- // This makes it so that future permission checks will be in the context of this
- // process rather than the caller's process. We will restore this before returning.
- final long identityToken = clearCallingIdentity();
+
if (cname != null) {
Slog.e(TAG, "cname not null.");
return;
}
+
+ // This makes it so that future permission checks will be in the context of this
+ // process rather than the caller's process. We will restore this before returning.
+ final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- SyncStorageEngine.EndPoint info;
- info = new SyncStorageEngine.EndPoint(account, authority, userId);
- syncManager.clearScheduledSyncOperations(info);
- syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
- }
+ SyncStorageEngine.EndPoint info;
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ getSyncManager().clearScheduledSyncOperations(info);
+ getSyncManager().cancelActiveSync(info, null /* all syncs for this adapter */, "API");
} finally {
restoreCallingIdentity(identityToken);
}
@@ -765,19 +751,16 @@ public final class ContentService extends IContentService.Stub {
@Override
public void cancelRequest(SyncRequest request) {
- SyncManager syncManager = getSyncManager();
- if (syncManager == null) return;
- int userId = UserHandle.getCallingUserId();
- final int callingUid = Binder.getCallingUid();
-
if (request.isPeriodic()) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
}
+ final int callingUid = Binder.getCallingUid();
Bundle extras = new Bundle(request.getBundle());
validateExtras(callingUid, extras);
+ int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
SyncStorageEngine.EndPoint info;
@@ -791,8 +774,8 @@ public final class ContentService extends IContentService.Stub {
"cancelRequest() by uid=" + callingUid);
}
// Cancel active syncs and clear pending syncs from the queue.
- syncManager.cancelScheduledSyncOperation(info, extras);
- syncManager.cancelActiveSync(info, extras, "API");
+ getSyncManager().cancelScheduledSyncOperation(info, extras);
+ getSyncManager().cancelActiveSync(info, extras, "API");
} finally {
restoreCallingIdentity(identityToken);
}
@@ -819,13 +802,13 @@ public final class ContentService extends IContentService.Stub {
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
- final int callingUid = Binder.getCallingUid();
+
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
+ final int callingUid = Binder.getCallingUid();
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- return syncManager.getSyncAdapterTypes(callingUid, userId);
+ return getSyncManager().getSyncAdapterTypes(callingUid, userId);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -835,13 +818,13 @@ public final class ContentService extends IContentService.Stub {
public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
- final int callingUid = Binder.getCallingUid();
+
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
+ final int callingUid = Binder.getCallingUid();
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, callingUid,
+ return getSyncManager().getSyncAdapterPackagesForAuthorityAsUser(authority, callingUid,
userId);
} finally {
restoreCallingIdentity(identityToken);
@@ -849,10 +832,12 @@ public final class ContentService extends IContentService.Stub {
}
@Override
+ @Nullable
public String getSyncAdapterPackageAsUser(@NonNull String accountType,
@NonNull String authority, @UserIdInt int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
+
final int callingUid = Binder.getCallingUid();
final long identityToken = clearCallingIdentity();
try {
@@ -884,15 +869,11 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine()
- .getSyncAutomatically(account, userId, providerName);
- }
+ return getSyncManager().getSyncStorageEngine()
+ .getSyncAutomatically(account, userId, providerName);
} finally {
restoreCallingIdentity(identityToken);
}
- return false;
}
@Override
@@ -921,11 +902,8 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
- providerName, sync, syncExemptionFlag, callingUid, callingPid);
- }
+ getSyncManager().getSyncStorageEngine().setSyncAutomatically(account, userId,
+ providerName, sync, syncExemptionFlag, callingUid, callingPid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -949,13 +927,13 @@ public final class ContentService extends IContentService.Stub {
if (!hasAccountAccess(true, account, callingUid)) {
return;
}
- validateExtras(callingUid, extras);
- int userId = UserHandle.getCallingUserId();
+ validateExtras(callingUid, extras);
pollFrequency = clampPeriod(pollFrequency);
long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
+ int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
SyncStorageEngine.EndPoint info =
@@ -983,15 +961,15 @@ public final class ContentService extends IContentService.Stub {
if (!hasAccountAccess(true, account, callingUid)) {
return;
}
+
validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
- getSyncManager()
- .removePeriodicSync(
- new SyncStorageEngine.EndPoint(account, authority, userId),
- extras, "removePeriodicSync() by uid=" + callingUid);
+ getSyncManager().removePeriodicSync(
+ new SyncStorageEngine.EndPoint(account, authority, userId),
+ extras, "removePeriodicSync() by uid=" + callingUid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1043,15 +1021,10 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.computeSyncable(
- account, userId, providerName, false);
- }
+ return getSyncManager().computeSyncable(account, userId, providerName, false);
} finally {
restoreCallingIdentity(identityToken);
}
- return -1;
}
@Override
@@ -1082,11 +1055,8 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.getSyncStorageEngine().setIsSyncable(
- account, userId, providerName, syncable, callingUid, callingPid);
- }
+ getSyncManager().getSyncStorageEngine().setIsSyncable(
+ account, userId, providerName, syncable, callingUid, callingPid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1110,14 +1080,10 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
- }
+ return getSyncManager().getSyncStorageEngine().getMasterSyncAutomatically(userId);
} finally {
restoreCallingIdentity(identityToken);
}
- return false;
}
@Override
@@ -1137,11 +1103,8 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
- getSyncExemptionForCaller(callingUid), callingUid, callingPid);
- }
+ getSyncManager().getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
+ getSyncExemptionForCaller(callingUid), callingUid, callingPid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1158,11 +1121,7 @@ public final class ContentService extends IContentService.Stub {
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager == null) {
- return false;
- }
- return syncManager.getSyncStorageEngine().isSyncActive(
+ return getSyncManager().getSyncStorageEngine().isSyncActive(
new SyncStorageEngine.EndPoint(account, authority, userId));
} finally {
restoreCallingIdentity(identityToken);
@@ -1191,7 +1150,7 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
return getSyncManager().getSyncStorageEngine()
- .getCurrentSyncsCopy(userId, canAccessAccounts);
+ .getCurrentSyncsCopy(userId, canAccessAccounts);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1207,6 +1166,7 @@ public final class ContentService extends IContentService.Stub {
* INTERACT_ACROSS_USERS_FULL permission.
*/
@Override
+ @Nullable
public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
ComponentName cname, int userId) {
if (TextUtils.isEmpty(authority)) {
@@ -1223,17 +1183,13 @@ public final class ContentService extends IContentService.Stub {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager == null) {
- return null;
- }
SyncStorageEngine.EndPoint info;
if (!(account == null || authority == null)) {
info = new SyncStorageEngine.EndPoint(account, authority, userId);
} else {
throw new IllegalArgumentException("Must call sync status with valid authority");
}
- return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
+ return getSyncManager().getSyncStorageEngine().getStatusByAuthority(info);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1256,9 +1212,6 @@ public final class ContentService extends IContentService.Stub {
}
final long identityToken = clearCallingIdentity();
- SyncManager syncManager = getSyncManager();
- if (syncManager == null) return false;
-
try {
SyncStorageEngine.EndPoint info;
if (!(account == null || authority == null)) {
@@ -1266,7 +1219,7 @@ public final class ContentService extends IContentService.Stub {
} else {
throw new IllegalArgumentException("Invalid authority specified");
}
- return syncManager.getSyncStorageEngine().isSyncPending(info);
+ return getSyncManager().getSyncStorageEngine().isSyncPending(info);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1277,9 +1230,8 @@ public final class ContentService extends IContentService.Stub {
final int callingUid = Binder.getCallingUid();
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null && callback != null) {
- syncManager.getSyncStorageEngine().addStatusChangeListener(
+ if (callback != null) {
+ getSyncManager().getSyncStorageEngine().addStatusChangeListener(
mask, callingUid, callback);
}
} finally {
@@ -1291,9 +1243,8 @@ public final class ContentService extends IContentService.Stub {
public void removeStatusChangeListener(ISyncStatusObserver callback) {
final long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null && callback != null) {
- syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
+ if (callback != null) {
+ getSyncManager().getSyncStorageEngine().removeStatusChangeListener(callback);
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 17215e5ae4ad..6de08aed9687 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -530,12 +530,36 @@ public class BrightnessTracker {
}
}
+ // Return the path to the given file, either the new path
+ // /data/system/$filename, or the old path /data/system_de/$filename if the
+ // file exists there but not at the new path. Only use this for EVENTS_FILE
+ // and AMBIENT_BRIGHTNESS_STATS_FILE.
+ //
+ // Explanation: this service previously incorrectly stored these two files
+ // directly in /data/system_de, instead of in /data/system where they should
+ // have been. As system_server no longer has write access to
+ // /data/system_de itself, these files were moved to /data/system. To
+ // lazily migrate the files, we simply read from the old path if it exists
+ // and the new one doesn't, and always write to the new path. Note that
+ // system_server doesn't have permission to delete the old files.
+ private AtomicFile getFileWithLegacyFallback(String filename) {
+ AtomicFile file = mInjector.getFile(filename);
+ if (file != null && !file.exists()) {
+ AtomicFile legacyFile = mInjector.getLegacyFile(filename);
+ if (legacyFile != null && legacyFile.exists()) {
+ Slog.i(TAG, "Reading " + filename + " from old location");
+ return legacyFile;
+ }
+ }
+ return file;
+ }
+
private void readEvents() {
synchronized (mEventsLock) {
// Read might prune events so mark as dirty.
mEventsDirty = true;
mEvents.clear();
- final AtomicFile readFrom = mInjector.getFile(EVENTS_FILE);
+ final AtomicFile readFrom = getFileWithLegacyFallback(EVENTS_FILE);
if (readFrom != null && readFrom.exists()) {
FileInputStream input = null;
try {
@@ -553,7 +577,7 @@ public class BrightnessTracker {
private void readAmbientBrightnessStats() {
mAmbientBrightnessStatsTracker = new AmbientBrightnessStatsTracker(mUserManager, null);
- final AtomicFile readFrom = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE);
+ final AtomicFile readFrom = getFileWithLegacyFallback(AMBIENT_BRIGHTNESS_STATS_FILE);
if (readFrom != null && readFrom.exists()) {
FileInputStream input = null;
try {
@@ -1123,6 +1147,10 @@ public class BrightnessTracker {
}
public AtomicFile getFile(String filename) {
+ return new AtomicFile(new File(Environment.getDataSystemDirectory(), filename));
+ }
+
+ public AtomicFile getLegacyFile(String filename) {
return new AtomicFile(new File(Environment.getDataSystemDeDirectory(), filename));
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index dbbd354a2ff0..84dfe860bc84 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -180,7 +180,7 @@ final class DisplayDeviceInfo {
public static final int TOUCH_VIRTUAL = 3;
/**
- * Diff result: The {@link #state} fields differ.
+ * Diff result: The {@link #state} or {@link #committedState} fields differ.
*/
public static final int DIFF_STATE = 1 << 0;
@@ -342,6 +342,13 @@ final class DisplayDeviceInfo {
public int state = Display.STATE_ON;
/**
+ * Display committed state.
+ *
+ * This matches {@link DisplayDeviceInfo#state} only after the power state change finishes.
+ */
+ public int committedState = Display.STATE_UNKNOWN;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -394,7 +401,7 @@ final class DisplayDeviceInfo {
*/
public int diff(DisplayDeviceInfo other) {
int diff = 0;
- if (state != other.state) {
+ if (state != other.state || committedState != other.committedState) {
diff |= DIFF_STATE;
}
if (colorMode != other.colorMode) {
@@ -468,6 +475,7 @@ final class DisplayDeviceInfo {
address = other.address;
deviceProductInfo = other.deviceProductInfo;
state = other.state;
+ committedState = other.committedState;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
frameRateOverrides = other.frameRateOverrides;
@@ -508,6 +516,7 @@ final class DisplayDeviceInfo {
}
sb.append(", deviceProductInfo ").append(deviceProductInfo);
sb.append(", state ").append(Display.stateToString(state));
+ sb.append(", committedState ").append(Display.stateToString(committedState));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6285ef1fdabd..b3434805ee41 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -241,10 +241,6 @@ public final class DisplayManagerService extends SystemService {
// This option may disable certain display adapters.
public boolean mSafeMode;
- // True if we are in a special boot mode where only core applications and
- // services should be started. This option may disable certain display adapters.
- public boolean mOnlyCore;
-
// All callback records indexed by calling process id.
public final SparseArray<CallbackRecord> mCallbacks =
new SparseArray<CallbackRecord>();
@@ -618,10 +614,9 @@ public final class DisplayManagerService extends SystemService {
/**
* Called when the system is ready to go.
*/
- public void systemReady(boolean safeMode, boolean onlyCore) {
+ public void systemReady(boolean safeMode) {
synchronized (mSyncRoot) {
mSafeMode = safeMode;
- mOnlyCore = onlyCore;
mSystemReady = true;
// Just in case the top inset changed before the system was ready. At this point, any
// relevant configuration should be in place.
@@ -1501,10 +1496,7 @@ public final class DisplayManagerService extends SystemService {
// In safe mode, we disable non-essential display adapters to give the user
// an opportunity to fix broken settings or other problems that might affect
// system stability.
- // In only-core mode, we disable non-essential display adapters to minimize
- // the number of dependencies that are started while in this mode and to
- // prevent problems that might occur due to the device being encrypted.
- return !mSafeMode && !mOnlyCore;
+ return !mSafeMode;
}
private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
@@ -2411,7 +2403,6 @@ public final class DisplayManagerService extends SystemService {
pw.println("DISPLAY MANAGER (dumpsys display)");
synchronized (mSyncRoot) {
- pw.println(" mOnlyCode=" + mOnlyCore);
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
pw.println(" mViewports=" + mViewports);
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 0b9d4debd16f..f98c7dff97e3 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -42,8 +42,8 @@ import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.Iterator;
-import java.util.LinkedList;
/**
* Controls the status of high-brightness mode for devices that support it. This class assumes that
@@ -110,11 +110,11 @@ class HighBrightnessModeController {
private long mRunningStartTimeMillis = -1;
/**
- * List of previous HBM-events ordered from most recent to least recent.
+ * Queue of previous HBM-events ordered from most recent to least recent.
* Meant to store only the events that fall into the most recent
- * {@link mHbmData.timeWindowMillis}.
+ * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}.
*/
- private LinkedList<HbmEvent> mEvents = new LinkedList<>();
+ private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>();
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
String displayUniqueId, float brightnessMin, float brightnessMax,
@@ -234,7 +234,7 @@ class HighBrightnessModeController {
mRunningStartTimeMillis = -1;
if (DEBUG) {
- Slog.d(TAG, "New HBM event: " + mEvents.getFirst());
+ Slog.d(TAG, "New HBM event: " + mEvents.peekFirst());
}
}
}
@@ -433,7 +433,7 @@ class HighBrightnessModeController {
// window by at least minTime. Basically, we're calculating the soonest time we can
// get {@code timeMinMillis} back to us.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
- final HbmEvent lastEvent = mEvents.getLast();
+ final HbmEvent lastEvent = mEvents.peekLast();
final long startTimePlusMinMillis =
Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
+ mHbmData.timeMinMillis;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 2a219289cf10..90a208e02326 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -198,6 +198,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
private int mState = Display.STATE_UNKNOWN;
+ private int mCommittedState = Display.STATE_UNKNOWN;
+
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -638,6 +640,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState;
+ mInfo.committedState = mCommittedState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
@@ -825,6 +828,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+ setCommittedState(state);
// If we're entering a suspended (but not OFF) power state and we
// have a sidekick available, tell it now that it can take control.
if (Display.isSuspendedState(state) && state != Display.STATE_OFF
@@ -839,6 +843,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
+ private void setCommittedState(int state) {
+ // After the display state is set, let's update the committed state.
+ getHandler().post(() -> {
+ synchronized (getSyncRoot()) {
+ mCommittedState = state;
+ updateDeviceInfoLocked();
+ }
+ });
+ }
+
private void setDisplayBrightness(float brightnessState,
float sdrBrightnessState) {
// brightnessState includes invalid, off and full range.
@@ -1104,6 +1118,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mDefaultModeId=" + mDefaultModeId);
pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
pw.println("mState=" + Display.stateToString(mState));
+ pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
pw.println("mBrightnessState=" + mBrightnessState);
pw.println("mBacklightAdapter=" + mBacklightAdapter);
pw.println("mAllmSupported=" + mAllmSupported);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 90b9967eef59..05341e0f876e 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -416,6 +416,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
mBaseDisplayInfo.state = deviceInfo.state;
+ mBaseDisplayInfo.committedState = deviceInfo.committedState;
mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index bb8a74493a16..2b95b11a09cd 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
@@ -129,7 +130,7 @@ public class IntentFirewall {
mObserver.startWatching();
}
- private PackageManagerInternal getPackageManager() {
+ PackageManagerInternal getPackageManager() {
if (mPackageManager == null) {
mPackageManager = LocalServices.getService(PackageManagerInternal.class);
}
@@ -623,12 +624,13 @@ public class IntentFirewall {
}
boolean signaturesMatch(int uid1, int uid2) {
+ final long token = Binder.clearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
- } catch (RemoteException ex) {
- Slog.e(TAG, "Remote exception while checking signatures", ex);
- return false;
+ // Compare signatures of two packages for different users.
+ return getPackageManager()
+ .checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index 007411962329..40684fab5c70 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -16,14 +16,11 @@
package com.android.server.firewall;
-import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Process;
-import android.os.RemoteException;
-import android.util.Slog;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,22 +34,12 @@ class SenderFilter {
private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
private static final String VAL_USER_ID = "userId";
- static boolean isPrivilegedApp(int callerUid, int callerPid) {
+ static boolean isPrivilegedApp(PackageManagerInternal pmi, int callerUid, int callerPid) {
if (callerUid == Process.SYSTEM_UID || callerUid == 0 ||
callerPid == Process.myPid() || callerPid == 0) {
return true;
}
-
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- != 0;
- } catch (RemoteException ex) {
- Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
- ex);
- }
-
- return false;
+ return pmi.isUidPrivileged(callerUid);
}
public static final FilterFactory FACTORY = new FilterFactory("sender") {
@@ -89,7 +76,7 @@ class SenderFilter {
@Override
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
int callerUid, int callerPid, String resolvedType, int receivingUid) {
- return isPrivilegedApp(callerUid, callerPid);
+ return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid);
}
};
@@ -97,8 +84,8 @@ class SenderFilter {
@Override
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
int callerUid, int callerPid, String resolvedType, int receivingUid) {
- return isPrivilegedApp(callerUid, callerPid) ||
- ifw.signaturesMatch(callerUid, receivingUid);
+ return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid)
+ || ifw.signaturesMatch(callerUid, receivingUid);
}
};
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 576a5ff4305e..26e38bdb6d51 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -306,16 +306,23 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
@Override
@ServiceThreadOnly
protected void onInitializeCecComplete(int initiatedBy) {
- if (initiatedBy == HdmiControlService.INITIATED_BY_SCREEN_ON) {
- oneTouchPlay(new IHdmiControlCallback.Stub() {
- @Override
- public void onComplete(int result) {
- if (result != HdmiControlManager.RESULT_SUCCESS) {
- Slog.w(TAG, "Failed to complete One Touch Play. result=" + result);
- }
- }
- });
+ if (initiatedBy != HdmiControlService.INITIATED_BY_SCREEN_ON) {
+ return;
}
+ @HdmiControlManager.PowerControlMode
+ String powerControlMode = mService.getHdmiCecConfig().getStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+ if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_NONE)) {
+ return;
+ }
+ oneTouchPlay(new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ if (result != HdmiControlManager.RESULT_SUCCESS) {
+ Slog.w(TAG, "Failed to complete One Touch Play. result=" + result);
+ }
+ }
+ });
}
@Override
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index d238dae634ad..e222c644da9e 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -27,6 +27,8 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import com.android.server.policy.WindowManagerPolicy;
+
/**
* An internal implementation of an {@link InputMonitor} that uses a spy window.
*
@@ -67,7 +69,9 @@ class GestureMonitorSpyWindow {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
- t.setLayer(mInputSurface, Integer.MAX_VALUE);
+ // Gesture monitor should be above handwriting event surface, hence setting it to
+ // WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER + 1
+ t.setLayer(mInputSurface, WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER + 1);
t.setPosition(mInputSurface, 0, 0);
t.setCrop(mInputSurface, null /* crop to parent surface */);
t.show(mInputSurface);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 72612a0468cd..0f0579cc3fa5 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import static android.provider.DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import android.annotation.NonNull;
@@ -115,7 +116,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -152,13 +152,16 @@ import java.util.function.Consumer;
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
static final String TAG = "InputManager";
- static final boolean DEBUG = false;
+ // To enable these logs, run: 'adb shell setprop log.tag.InputManager DEBUG' (requires restart)
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
// Feature flag name for the deep press feature
private static final String DEEP_PRESS_ENABLED = "deep_press_enabled";
+ // Feature flag name for the strategy to be used in VelocityTracker
+ private static final String VELOCITYTRACKER_STRATEGY_PROPERTY = "velocitytracker_strategy";
private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
@@ -172,19 +175,6 @@ public class InputManagerService extends IInputManager.Stub
private static final AdditionalDisplayInputProperties
DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties();
- /**
- * We know the issue and are working to fix it, so suppressing the toast to not annoy
- * dogfooders.
- *
- * TODO(b/169067926): Remove this
- */
- private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = {
- "com.snapchat.android" // b/173297887
- };
-
- /** TODO(b/169067926): Remove this. */
- private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
-
private final NativeInputManagerService mNative;
private final Context mContext;
@@ -381,6 +371,8 @@ public class InputManagerService extends IInputManager.Stub
public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
+ private final String mVelocityTrackerStrategy;
+
/** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
final boolean mUseDevInputEventForAudioJack;
@@ -436,6 +428,9 @@ public class InputManagerService extends IInputManager.Stub
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
+ mVelocityTrackerStrategy = DeviceConfig.getProperty(
+ NAMESPACE_INPUT_NATIVE_BOOT, VELOCITYTRACKER_STRATEGY_PROPERTY);
+
injector.registerLocalService(new LocalService());
}
@@ -484,7 +479,6 @@ public class InputManagerService extends IInputManager.Stub
registerAccessibilityLargePointerSettingObserver();
registerLongPressTimeoutObserver();
registerMaximumObscuringOpacityForTouchSettingObserver();
- registerBlockUntrustedTouchesModeSettingObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
@@ -501,7 +495,6 @@ public class InputManagerService extends IInputManager.Stub
updateAccessibilityLargePointerFromSettings();
updateDeepPressStatusFromSettings("just booted");
updateMaximumObscuringOpacityForTouchFromSettings();
- updateBlockUntrustedTouchesModeFromSettings();
}
// TODO(BT) Pass in parameter for bluetooth system
@@ -932,6 +925,11 @@ public class InputManagerService extends IInputManager.Stub
return mNative.verifyInputEvent(event);
}
+ @Override // Binder call
+ public String getVelocityTrackerStrategy() {
+ return mVelocityTrackerStrategy;
+ }
+
/**
* Gets information about the input device with the specified id.
* @param deviceId The device id.
@@ -1058,6 +1056,10 @@ public class InputManagerService extends IInputManager.Stub
final InputDevice inputDevice = mInputDevices[i];
deviceIdAndGeneration[i * 2] = inputDevice.getId();
deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
+ if (DEBUG) {
+ Log.d(TAG, "device " + inputDevice.getId() + " generation "
+ + inputDevice.getGeneration());
+ }
if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
if (!containsInputDeviceWithDescriptor(oldInputDevices,
@@ -1581,8 +1583,8 @@ public class InputManagerService extends IInputManager.Stub
layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
}
if (DEBUG) {
- Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
- + layout);
+ Slog.d(TAG, "getCurrentKeyboardLayoutForInputDevice() "
+ + identifier.toString() + ": " + layout);
}
return layout;
}
@@ -1604,7 +1606,9 @@ public class InputManagerService extends IInputManager.Stub
try {
if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
if (DEBUG) {
- Slog.d(TAG, "Saved keyboard layout using " + key);
+ Slog.d(TAG, "setCurrentKeyboardLayoutForInputDevice() " + identifier
+ + " key: " + key
+ + " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
}
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
}
@@ -1924,23 +1928,6 @@ public class InputManagerService extends IInputManager.Stub
}, UserHandle.USER_ALL);
}
- private void registerBlockUntrustedTouchesModeSettingObserver() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE),
- /* notifyForDescendants */ true,
- new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- updateBlockUntrustedTouchesModeFromSettings();
- }
- }, UserHandle.USER_ALL);
- }
-
- private void updateBlockUntrustedTouchesModeFromSettings() {
- final int mode = InputManager.getInstance().getBlockUntrustedTouchesMode(mContext);
- mNative.setBlockUntrustedTouchesMode(mode);
- }
-
private void registerMaximumObscuringOpacityForTouchSettingObserver() {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH),
@@ -2391,7 +2378,7 @@ public class InputManagerService extends IInputManager.Stub
public void removePortAssociation(@NonNull String inputPort) {
if (!checkCallingPermission(
android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
- "clearPortAssociations()")) {
+ "removePortAssociation()")) {
throw new SecurityException(
"Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
}
@@ -2407,7 +2394,7 @@ public class InputManagerService extends IInputManager.Stub
public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
if (!checkCallingPermission(
android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
- "addNameAssociation()")) {
+ "addUniqueIdAssociation()")) {
throw new SecurityException(
"Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
}
@@ -2902,22 +2889,6 @@ public class InputManagerService extends IInputManager.Stub
mWindowManagerCallbacks.notifyDropWindow(token, x, y);
}
- // Native callback
- @SuppressWarnings("unused")
- private void notifyUntrustedTouch(String packageName) {
- // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
- if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
- PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
- Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
- return;
- }
- DisplayThread.getHandler().post(() ->
- Toast.makeText(mContext,
- "Touch obscured by " + packageName
- + " will be blocked. Check go/untrusted-touches",
- Toast.LENGTH_SHORT).show());
- }
-
// Native callback.
@SuppressWarnings("unused")
private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) {
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 9cf80737e67d..3d1e4410f742 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -68,8 +68,6 @@ public interface NativeInputManagerService {
void setMaximumObscuringOpacityForTouch(float opacity);
- void setBlockUntrustedTouchesMode(int mode);
-
/**
* Inject an input event into the system.
*
@@ -248,12 +246,8 @@ public interface NativeInputManagerService {
public native void setMaximumObscuringOpacityForTouch(float opacity);
@Override
- public native void setBlockUntrustedTouchesMode(int mode);
-
- @Override
public native int injectInputEvent(InputEvent event, boolean injectIntoUid, int uid,
- int syncMode,
- int timeoutMillis, int policyFlags);
+ int syncMode, int timeoutMillis, int policyFlags);
@Override
public native VerifiedInputEvent verifyInputEvent(InputEvent event);
diff --git a/services/core/java/com/android/server/input/OWNERS b/services/core/java/com/android/server/input/OWNERS
index 82c6ee12c7ae..4c20c4dc9d35 100644
--- a/services/core/java/com/android/server/input/OWNERS
+++ b/services/core/java/com/android/server/input/OWNERS
@@ -1,3 +1 @@
-lzye@google.com
-michaelwr@google.com
-svv@google.com
+include /INPUT_OWNERS
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 8180e66166d9..5438faa8793e 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -27,6 +27,8 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import com.android.server.policy.WindowManagerPolicy;
+
final class HandwritingEventReceiverSurface {
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
@@ -36,7 +38,8 @@ final class HandwritingEventReceiverSurface {
// is above gesture monitors, then edge-back and swipe-up gestures won't work when this surface
// is intercepting.
// TODO(b/217538817): Specify the ordering in WM by usage.
- private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
+ private static final int HANDWRITING_SURFACE_LAYER =
+ WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER;
private final InputWindowHandle mWindowHandle;
private final InputChannel mClientChannel;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 57d89dae588e..08420a1822e0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -75,6 +75,11 @@ public abstract class InputMethodManagerInternal {
public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId);
/**
+ * Returns {@code true} if currently selected IME supports Stylus handwriting.
+ */
+ public abstract boolean isStylusHandwritingAvailable();
+
+ /**
* Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from
* the input method.
*
@@ -256,6 +261,11 @@ public abstract class InputMethodManagerInternal {
@Override
public void maybeFinishStylusHandwriting() {
}
+
+ @Override
+ public boolean isStylusHandwritingAvailable() {
+ return false;
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1a1c265f568d..85c6ca6be4bc 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2149,6 +2149,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ @Override
+ public boolean isStylusHandwritingAvailable() {
+ synchronized (ImfLock.class) {
+ return mBindingController.supportsStylusHandwriting();
+ }
+ }
+
@GuardedBy("ImfLock.class")
private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness) {
@@ -3188,6 +3195,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
hideStatusBarIconLocked();
mInFullscreenMode = false;
+ mWindowManagerInternal.setDismissImeOnBackKeyPressed(false);
}
@BinderThread
@@ -4855,7 +4863,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@BinderThread
- private void hideMySoftInput(@NonNull IBinder token, int flags) {
+ private void hideMySoftInput(@NonNull IBinder token, int flags,
+ @SoftInputShowHideReason int reason) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
@@ -4863,10 +4872,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
final long ident = Binder.clearCallingIdentity();
try {
- hideCurrentInputLocked(
- mLastImeTargetWindow, flags, null,
- SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
-
+ hideCurrentInputLocked(mLastImeTargetWindow, flags, null, reason);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4884,7 +4890,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final long ident = Binder.clearCallingIdentity();
try {
showCurrentInputLocked(mLastImeTargetWindow, flags, null,
- SoftInputShowHideReason.SHOW_MY_SOFT_INPUT);
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5830,6 +5836,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.removeMessages(MSG_FINISH_HANDWRITING);
mHandler.obtainMessage(MSG_FINISH_HANDWRITING).sendToTarget();
}
+
+ @Override
+ public boolean isStylusHandwritingAvailable() {
+ return InputMethodManagerService.this.isStylusHandwritingAvailable();
+ }
}
@BinderThread
@@ -6696,11 +6707,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
- public void hideMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+ public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason,
+ AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
- mImms.hideMySoftInput(mToken, flags);
+ mImms.hideMySoftInput(mToken, flags, reason);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index e5eed9928411..c6ea5123d903 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1030,11 +1030,11 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
@Override
+ @RequiresPermission(INTERACT_ACROSS_USERS)
public void addProviderRequestListener(IProviderRequestListener listener) {
- if (mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.addProviderRequestListener(listener);
- }
+ mContext.enforceCallingOrSelfPermission(INTERACT_ACROSS_USERS, null);
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.addProviderRequestListener(listener);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 0e4bbbb7a412..d5a759d6c604 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -212,7 +212,10 @@ class LockSettingsShellCommand extends ShellCommand {
if ("--old".equals(opt)) {
mOld = getNextArgRequired();
} else if ("--user".equals(opt)) {
- mCurrentUserId = Integer.parseInt(getNextArgRequired());
+ mCurrentUserId = UserHandle.parseUserArg(getNextArgRequired());
+ if (mCurrentUserId == UserHandle.USER_CURRENT) {
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ }
} else {
getErrPrintWriter().println("Unknown option: " + opt);
throw new IllegalArgumentException();
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 1bcc21e66302..04cacee32283 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -412,7 +412,6 @@ public final class LogcatManagerService extends SystemService {
private void processNewLogAccessRequest(LogAccessClient client) {
boolean isInstrumented = mActivityManagerInternal.getInstrumentationSourceUid(client.mUid)
!= android.os.Process.INVALID_UID;
-
// The instrumented apks only run for testing, so we don't check user permission.
if (isInstrumented) {
onAccessApprovedForClient(client);
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index b75ba75e028b..337d5e51ddfb 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -63,8 +63,6 @@ class MediaSessionStack {
*/
private MediaSessionRecordImpl mMediaButtonSession;
- private MediaSessionRecordImpl mCachedVolumeDefault;
-
/**
* Cache the result of the {@link #getActiveSessions} per user.
*/
@@ -145,9 +143,6 @@ class MediaSessionStack {
mSessions.remove(record);
mSessions.add(0, record);
clearCache(record.getUserId());
- } else if (record.checkPlaybackActiveState(false)) {
- // Just clear the volume cache when a state goes inactive
- mCachedVolumeDefault = null;
}
// In most cases, playback state isn't needed for finding media button session,
@@ -318,15 +313,11 @@ class MediaSessionStack {
}
public MediaSessionRecordImpl getDefaultVolumeSession() {
- if (mCachedVolumeDefault != null) {
- return mCachedVolumeDefault;
- }
List<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
if (record.checkPlaybackActiveState(true) && record.canHandleVolumeKey()) {
- mCachedVolumeDefault = record;
return record;
}
}
@@ -406,7 +397,6 @@ class MediaSessionStack {
}
private void clearCache(int userId) {
- mCachedVolumeDefault = null;
mCachedActiveLists.remove(userId);
// mCachedActiveLists may also include the list of sessions for UserHandle.USER_ALL,
// so they also need to be cleared.
diff --git a/services/core/java/com/android/server/media/TEST_MAPPING b/services/core/java/com/android/server/media/TEST_MAPPING
new file mode 100644
index 000000000000..1b49093a66d8
--- /dev/null
+++ b/services/core/java/com/android/server/media/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaBetterTogetherTestCases"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index e6bc79679a8f..5a40b30551b6 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1447,6 +1447,16 @@ abstract public class ManagedServices {
}
}
+ @VisibleForTesting
+ void reregisterService(final ComponentName cn, final int userId) {
+ // If rebinding a package that died, ensure it still has permission
+ // after the rebind delay
+ if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
+ || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
+ registerService(cn, userId);
+ }
+ }
+
/**
* Inject a system service into the management list.
*/
@@ -1545,12 +1555,9 @@ abstract public class ManagedServices {
unbindService(this, name, userid);
if (!mServicesRebinding.contains(servicesBindingTag)) {
mServicesRebinding.add(servicesBindingTag);
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- registerService(name, userid);
- }
- }, ON_BINDING_DIED_REBIND_DELAY_MS);
+ mHandler.postDelayed(() ->
+ reregisterService(name, userid),
+ ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+ " as a previous rebind attempt was made: " + name);
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index a9b2570a3dda..e09f7b09b4d1 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -40,11 +40,12 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.List;
import java.util.Set;
/**
@@ -76,7 +77,7 @@ public class NotificationHistoryDatabase {
private final Handler mFileWriteHandler;
@VisibleForTesting
// List of files holding history information, sorted newest to oldest
- final LinkedList<AtomicFile> mHistoryFiles;
+ final List<AtomicFile> mHistoryFiles;
private final File mHistoryDir;
private final File mVersionFile;
// Current version of the database files schema
@@ -94,7 +95,7 @@ public class NotificationHistoryDatabase {
mFileWriteHandler = fileWriteHandler;
mVersionFile = new File(dir, "version");
mHistoryDir = new File(dir, "history");
- mHistoryFiles = new LinkedList<>();
+ mHistoryFiles = new ArrayList<>();
mBuffer = new NotificationHistory();
mWriteBufferRunnable = new WriteBufferRunnable();
@@ -133,7 +134,7 @@ public class NotificationHistoryDatabase {
safeParseLong(lhs.getName())));
for (File file : files) {
- mHistoryFiles.addLast(new AtomicFile(file));
+ mHistoryFiles.add(new AtomicFile(file));
}
}
@@ -411,7 +412,7 @@ public class NotificationHistoryDatabase {
+ file.getBaseFile().getAbsolutePath());
try {
writeLocked(file, mBuffer);
- mHistoryFiles.addFirst(file);
+ mHistoryFiles.add(0, file);
mBuffer = new NotificationHistory();
scheduleDeletion(file.getBaseFile(), time, HISTORY_RETENTION_DAYS);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d1e0b0474b61..d3580a4e3317 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -96,6 +96,7 @@ import static android.service.notification.NotificationListenerService.REASON_ER
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
@@ -517,7 +518,7 @@ public class NotificationManagerService extends SystemService {
private ActivityManagerInternal mAmi;
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
- private PackageManagerInternal mPackageManagerInternal;
+ PackageManagerInternal mPackageManagerInternal;
private PermissionPolicyInternal mPermissionPolicyInternal;
AudioManager mAudioManager;
AudioManagerInternal mAudioManagerInternal;
@@ -9611,7 +9612,7 @@ public class NotificationManagerService extends SystemService {
int numNotifications = mNotificationList.size();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
- mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
+ mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN,
rec.getStats());
}
@@ -9798,7 +9799,7 @@ public class NotificationManagerService extends SystemService {
* notifications visible to the given listener.
*/
@GuardedBy("mNotificationLock")
- private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
+ NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
final int N = mNotificationList.size();
final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
@@ -10913,7 +10914,7 @@ public class NotificationManagerService extends SystemService {
TrimCache trimCache = new TrimCache(sbn);
for (final ManagedServiceInfo info : getServices()) {
- boolean sbnVisible = isVisibleToListener(sbn, r. getNotificationType(), info);
+ boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info);
boolean oldSbnVisible = (oldSbn != null)
&& isVisibleToListener(oldSbn, old.getNotificationType(), info);
// This notification hasn't been and still isn't visible -> ignore.
@@ -10943,12 +10944,17 @@ public class NotificationManagerService extends SystemService {
info, oldSbnLightClone, update, null, REASON_USER_STOPPED));
continue;
}
-
// Grant access before listener is notified
final int targetUserId = (info.userid == UserHandle.USER_ALL)
? UserHandle.USER_SYSTEM : info.userid;
updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
+ mPackageManagerInternal.grantImplicitAccess(
+ targetUserId, null /* intent */,
+ UserHandle.getAppId(info.uid),
+ sbn.getUid(),
+ false /* direct */, false /* retainOnUpdate */);
+
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
mHandler.post(() -> notifyPosted(info, sbnToPost, update));
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9e0c97502c4f..de9102a69a2e 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -121,6 +121,7 @@ public class ZenModeHelper {
protected final RingerModeDelegate mRingerModeDelegate = new
RingerModeDelegate();
@VisibleForTesting protected final ZenModeConditions mConditions;
+ Object mConfigsLock = new Object();
@VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
private final Metrics mMetrics = new Metrics();
private final ConditionProviders.Config mServiceConfig;
@@ -153,7 +154,9 @@ public class ZenModeHelper {
mDefaultConfig = readDefaultConfig(mContext.getResources());
updateDefaultAutomaticRuleNames();
mConfig = mDefaultConfig.copy();
- mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
+ synchronized (mConfigsLock) {
+ mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
+ }
mConsolidatedPolicy = mConfig.toNotificationPolicy();
mSettingsObserver = new SettingsObserver(mHandler);
@@ -233,7 +236,9 @@ public class ZenModeHelper {
public void onUserRemoved(int user) {
if (user < UserHandle.USER_SYSTEM) return;
if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
- mConfigs.remove(user);
+ synchronized (mConfigsLock) {
+ mConfigs.remove(user);
+ }
}
public void onUserUnlocked(int user) {
@@ -248,7 +253,12 @@ public class ZenModeHelper {
if (mUser == user || user < UserHandle.USER_SYSTEM) return;
mUser = user;
if (DEBUG) Log.d(TAG, reason + " u=" + user);
- ZenModeConfig config = mConfigs.get(user);
+ ZenModeConfig config = null;
+ synchronized (mConfigsLock) {
+ if (mConfigs.get(user) != null) {
+ config = mConfigs.get(user).copy();
+ }
+ }
if (config == null) {
if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
config = mDefaultConfig.copy();
@@ -685,9 +695,11 @@ public class ZenModeHelper {
pw.println(Global.zenModeToString(mZenMode));
pw.print(prefix);
pw.println("mConsolidatedPolicy=" + mConsolidatedPolicy.toString());
- final int N = mConfigs.size();
- for (int i = 0; i < N; i++) {
- dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
+ synchronized(mConfigsLock) {
+ final int N = mConfigs.size();
+ for (int i = 0; i < N; i++) {
+ dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
+ }
}
pw.print(prefix); pw.print("mUser="); pw.println(mUser);
synchronized (mConfig) {
@@ -787,7 +799,7 @@ public class ZenModeHelper {
public void writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId)
throws IOException {
- synchronized (mConfigs) {
+ synchronized (mConfigsLock) {
final int n = mConfigs.size();
for (int i = 0; i < n; i++) {
if (forBackup && mConfigs.keyAt(i) != userId) {
@@ -883,14 +895,18 @@ public class ZenModeHelper {
}
if (config.user != mUser) {
// simply store away for background users
- mConfigs.put(config.user, config);
+ synchronized (mConfigsLock) {
+ mConfigs.put(config.user, config);
+ }
if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
return true;
}
// handle CPS backed conditions - danger! may modify config
mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
- mConfigs.put(config.user, config);
+ synchronized (mConfigsLock) {
+ mConfigs.put(config.user, config);
+ }
if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
ZenLog.traceConfig(reason, mConfig, config);
@@ -1211,7 +1227,7 @@ public class ZenModeHelper {
* Generate pulled atoms about do not disturb configurations.
*/
public void pullRules(List<StatsEvent> events) {
- synchronized (mConfig) {
+ synchronized (mConfigsLock) {
final int numConfigs = mConfigs.size();
for (int i = 0; i < numConfigs; i++) {
final int user = mConfigs.keyAt(i);
diff --git a/services/core/java/com/android/server/oemlock/OemLockService.java b/services/core/java/com/android/server/oemlock/OemLockService.java
index f19d353a1f7b..6735d55bf518 100644
--- a/services/core/java/com/android/server/oemlock/OemLockService.java
+++ b/services/core/java/com/android/server/oemlock/OemLockService.java
@@ -16,11 +16,15 @@
package com.android.server.oemlock;
-import android.Manifest;
+import static android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE;
+import static android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE;
+import static android.Manifest.permission.OEM_UNLOCK_STATE;
+import static android.Manifest.permission.READ_OEM_UNLOCK_STATE;
+
+import android.annotation.EnforcePermission;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.hardware.oemlock.V1_0.IOemLock;
import android.os.Binder;
import android.os.Bundle;
@@ -114,9 +118,8 @@ public class OemLockService extends SystemService {
private final IBinder mService = new IOemLockService.Stub() {
@Override
@Nullable
+ @EnforcePermission(MANAGE_CARRIER_OEM_UNLOCK_STATE)
public String getLockName() {
- enforceManageCarrierOemUnlockPermission();
-
final long token = Binder.clearCallingIdentity();
try {
return mOemLock.getLockName();
@@ -126,8 +129,8 @@ public class OemLockService extends SystemService {
}
@Override
+ @EnforcePermission(MANAGE_CARRIER_OEM_UNLOCK_STATE)
public void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
- enforceManageCarrierOemUnlockPermission();
enforceUserIsAdmin();
final long token = Binder.clearCallingIdentity();
@@ -139,9 +142,8 @@ public class OemLockService extends SystemService {
}
@Override
+ @EnforcePermission(MANAGE_CARRIER_OEM_UNLOCK_STATE)
public boolean isOemUnlockAllowedByCarrier() {
- enforceManageCarrierOemUnlockPermission();
-
final long token = Binder.clearCallingIdentity();
try {
return mOemLock.isOemUnlockAllowedByCarrier();
@@ -153,13 +155,12 @@ public class OemLockService extends SystemService {
// The user has the final say so if they allow unlock, then the device allows the bootloader
// to OEM unlock it.
@Override
+ @EnforcePermission(MANAGE_USER_OEM_UNLOCK_STATE)
public void setOemUnlockAllowedByUser(boolean allowedByUser) {
if (ActivityManager.isUserAMonkey()) {
// Prevent a monkey from changing this
return;
}
-
- enforceManageUserOemUnlockPermission();
enforceUserIsAdmin();
final long token = Binder.clearCallingIdentity();
@@ -180,9 +181,8 @@ public class OemLockService extends SystemService {
}
@Override
+ @EnforcePermission(MANAGE_USER_OEM_UNLOCK_STATE)
public boolean isOemUnlockAllowedByUser() {
- enforceManageUserOemUnlockPermission();
-
final long token = Binder.clearCallingIdentity();
try {
return mOemLock.isOemUnlockAllowedByDevice();
@@ -197,9 +197,8 @@ public class OemLockService extends SystemService {
* TODO: Figure out better place to run sync e.g. adding new API
*/
@Override
+ @EnforcePermission(anyOf = {READ_OEM_UNLOCK_STATE, OEM_UNLOCK_STATE})
public boolean isOemUnlockAllowed() {
- enforceOemUnlockReadPermission();
-
final long token = Binder.clearCallingIdentity();
try {
boolean allowed = mOemLock.isOemUnlockAllowedByCarrier()
@@ -212,9 +211,8 @@ public class OemLockService extends SystemService {
}
@Override
+ @EnforcePermission(anyOf = {READ_OEM_UNLOCK_STATE, OEM_UNLOCK_STATE})
public boolean isDeviceOemUnlocked() {
- enforceOemUnlockReadPermission();
-
String locked = SystemProperties.get(FLASH_LOCK_PROP);
switch (locked) {
case FLASH_LOCK_UNLOCKED:
@@ -244,28 +242,6 @@ public class OemLockService extends SystemService {
.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM);
}
- private void enforceManageCarrierOemUnlockPermission() {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE,
- "Can't manage OEM unlock allowed by carrier");
- }
-
- private void enforceManageUserOemUnlockPermission() {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE,
- "Can't manage OEM unlock allowed by user");
- }
-
- private void enforceOemUnlockReadPermission() {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_OEM_UNLOCK_STATE)
- == PackageManager.PERMISSION_DENIED
- && mContext.checkCallingOrSelfPermission(Manifest.permission.OEM_UNLOCK_STATE)
- == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException("Can't access OEM unlock state. Requires "
- + "READ_OEM_UNLOCK_STATE or OEM_UNLOCK_STATE permission.");
- }
- }
-
private void enforceUserIsAdmin() {
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 903d02afc307..f3cb7fb6107c 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -19,6 +19,7 @@ package com.android.server.om;
import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.om.OverlayInfo;
import android.content.om.OverlayableInfo;
@@ -33,6 +34,8 @@ import android.util.Slog;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -56,6 +59,18 @@ final class IdmapManager {
VENDOR_IS_Q_OR_LATER = isQOrLater;
}
+ static final int IDMAP_NOT_EXIST = 0;
+ static final int IDMAP_IS_VERIFIED = 1;
+ static final int IDMAP_IS_MODIFIED = 1 << 1;
+
+ @IntDef(flag = true, prefix = { "IDMAP_" }, value = {
+ IDMAP_NOT_EXIST,
+ IDMAP_IS_VERIFIED,
+ IDMAP_IS_MODIFIED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IdmapStatus {}
+
private final IdmapDaemon mIdmapDaemon;
private final PackageManagerHelper mPackageManager;
@@ -76,8 +91,14 @@ final class IdmapManager {
/**
* Creates the idmap for the target/overlay combination and returns whether the idmap file was
* modified.
+ * @return the status of the specific idmap file. It's one of the following.<ul>
+ * <li>{@link #IDMAP_NOT_EXIST} means the idmap file is not existed.</li>
+ * <li>{@link #IDMAP_IS_VERIFIED} means the idmap file is verified by Idmap2d.</li>
+ * <li>{@link #IDMAP_IS_MODIFIED | IDMAP_IS_VERIFIED } means the idmap file is modified and
+ * verified by Idmap2d.</li>
+ * </ul>.
*/
- boolean createIdmap(@NonNull final AndroidPackage targetPackage,
+ @IdmapStatus int createIdmap(@NonNull final AndroidPackage targetPackage,
@NonNull final AndroidPackage overlayPackage, String overlayBasePath,
String overlayName, int userId) {
if (DEBUG) {
@@ -90,14 +111,15 @@ final class IdmapManager {
boolean enforce = enforceOverlayable(overlayPackage);
if (mIdmapDaemon.verifyIdmap(targetPath, overlayBasePath, overlayName, policies,
enforce, userId)) {
- return false;
+ return IDMAP_IS_VERIFIED;
}
- return mIdmapDaemon.createIdmap(targetPath, overlayBasePath, overlayName, policies,
- enforce, userId) != null;
+ final boolean idmapCreated = mIdmapDaemon.createIdmap(targetPath, overlayBasePath,
+ overlayName, policies, enforce, userId) != null;
+ return (idmapCreated) ? IDMAP_IS_MODIFIED | IDMAP_IS_VERIFIED : IDMAP_NOT_EXIST;
} catch (Exception e) {
Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
+ overlayBasePath, e);
- return false;
+ return IDMAP_NOT_EXIST;
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8ecc607603a1..0ba8d2c87e99 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -1255,7 +1255,7 @@ public final class OverlayManagerService extends SystemService {
// to be installed for different users: ignore userId for now.
try {
return mPackageManager.checkSignatures(
- packageName1, packageName2) == SIGNATURE_MATCH;
+ packageName1, packageName2, userId) == SIGNATURE_MATCH;
} catch (RemoteException e) {
// Intentionally left blank
}
@@ -1477,22 +1477,25 @@ public final class OverlayManagerService extends SystemService {
targetPackageNames = pm.getTargetPackageNames(userId);
}
- final Map<String, OverlayPaths> pendingChanges =
+ final ArrayMap<String, OverlayPaths> pendingChanges =
new ArrayMap<>(targetPackageNames.size());
synchronized (mLock) {
final OverlayPaths frameworkOverlays =
- mImpl.getEnabledOverlayPaths("android", userId);
+ mImpl.getEnabledOverlayPaths("android", userId, false);
for (final String targetPackageName : targetPackageNames) {
final OverlayPaths.Builder list = new OverlayPaths.Builder();
+ list.addAll(frameworkOverlays);
if (!"android".equals(targetPackageName)) {
- list.addAll(frameworkOverlays);
+ list.addAll(mImpl.getEnabledOverlayPaths(targetPackageName, userId, true));
}
- list.addAll(mImpl.getEnabledOverlayPaths(targetPackageName, userId));
pendingChanges.put(targetPackageName, list.build());
}
}
final HashSet<String> updatedPackages = new HashSet<>();
+ final HashSet<String> invalidPackages = new HashSet<>();
+ pm.setEnabledOverlayPackages(userId, pendingChanges, updatedPackages, invalidPackages);
+
for (final String targetPackageName : targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
@@ -1500,11 +1503,10 @@ public final class OverlayManagerService extends SystemService {
+ "] userId=" + userId);
}
- if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName),
- updatedPackages)) {
- Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
+ if (invalidPackages.contains(targetPackageName)) {
+ Slog.e(TAG, TextUtils.formatSimple(
+ "Failed to change enabled overlays for %s user %d", targetPackageName,
+ userId));
}
}
return new ArrayList<>(updatedPackages);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 38781fad76fd..dade7aa09283 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -24,6 +24,9 @@ import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED;
import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.server.om.IdmapManager.IDMAP_IS_MODIFIED;
+import static com.android.server.om.IdmapManager.IDMAP_IS_VERIFIED;
+import static com.android.server.om.IdmapManager.IDMAP_NOT_EXIST;
import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
@@ -741,7 +744,7 @@ final class OverlayManagerServiceImpl {
}
OverlayPaths getEnabledOverlayPaths(@NonNull final String targetPackageName,
- final int userId) {
+ final int userId, boolean includeImmutableOverlays) {
final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
userId);
final OverlayPaths.Builder paths = new OverlayPaths.Builder();
@@ -751,6 +754,9 @@ final class OverlayManagerServiceImpl {
if (!oi.isEnabled()) {
continue;
}
+ if (!includeImmutableOverlays && !oi.isMutable) {
+ continue;
+ }
if (oi.isFabricated()) {
paths.addNonApkPath(oi.baseCodePath);
} else {
@@ -785,15 +791,18 @@ final class OverlayManagerServiceImpl {
// Immutable RROs targeting to "android", ie framework-res.apk, are handled by native
// layers.
final OverlayInfo updatedOverlayInfo = mSettings.getOverlayInfo(overlay, userId);
+ @IdmapManager.IdmapStatus int idmapStatus = IDMAP_NOT_EXIST;
if (targetPackage != null && !("android".equals(info.getTargetPackageName())
&& !isPackageConfiguredMutable(overlayPackage))) {
- modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage,
- updatedOverlayInfo.baseCodePath, overlay.getOverlayName(), userId);
+ idmapStatus = mIdmapManager.createIdmap(targetPackage,
+ overlayPackage, updatedOverlayInfo.baseCodePath, overlay.getOverlayName(),
+ userId);
+ modified |= (idmapStatus & IDMAP_IS_MODIFIED) != 0;
}
final @OverlayInfo.State int currentState = mSettings.getState(overlay, userId);
final @OverlayInfo.State int newState = calculateNewState(updatedOverlayInfo, targetPackage,
- userId, flags);
+ userId, flags, idmapStatus);
if (currentState != newState) {
if (DEBUG) {
Slog.d(TAG, String.format("%s:%d: %s -> %s",
@@ -808,7 +817,8 @@ final class OverlayManagerServiceImpl {
}
private @OverlayInfo.State int calculateNewState(@NonNull final OverlayInfo info,
- @Nullable final AndroidPackage targetPackage, final int userId, final int flags)
+ @Nullable final AndroidPackage targetPackage, final int userId, final int flags,
+ @IdmapManager.IdmapStatus final int idmapStatus)
throws OverlayManagerSettings.BadKeyException {
if ((flags & FLAG_TARGET_IS_BEING_REPLACED) != 0) {
return STATE_TARGET_IS_BEING_REPLACED;
@@ -822,8 +832,10 @@ final class OverlayManagerServiceImpl {
return STATE_MISSING_TARGET;
}
- if (!mIdmapManager.idmapExists(info)) {
- return STATE_NO_IDMAP;
+ if ((idmapStatus & IDMAP_IS_VERIFIED) == 0) {
+ if (!mIdmapManager.idmapExists(info)) {
+ return STATE_NO_IDMAP;
+ }
}
final boolean enabled = mSettings.getEnabled(info.getOverlayIdentifier(), userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 55bca1733d37..9e3922607dab 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -178,18 +178,12 @@ final class OverlayManagerSettings {
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) {
- // Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
- // ignored in OverlayManagerService.
final List<SettingsItem> items = selectWhereTarget(targetPackageName, userId);
- items.removeIf(OverlayManagerSettings::isImmutableFrameworkOverlay);
return CollectionUtils.map(items, SettingsItem::getOverlayInfo);
}
ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
- // Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
- // ignored in OverlayManagerService.
final List<SettingsItem> items = selectWhereUser(userId);
- items.removeIf(OverlayManagerSettings::isImmutableFrameworkOverlay);
final ArrayMap<String, List<OverlayInfo>> targetInfos = new ArrayMap<>();
for (int i = 0, n = items.size(); i < n; i++) {
@@ -234,10 +228,6 @@ final class OverlayManagerSettings {
return mItems.stream().mapToInt(SettingsItem::getUserId).distinct().toArray();
}
- private static boolean isImmutableFrameworkOverlay(@NonNull SettingsItem item) {
- return !item.isMutable() && "android".equals(item.getTargetPackageName());
- }
-
/**
* Returns true if the settings were modified, false if they remain the same.
*/
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 89939a31321f..bdde4f6ad86b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -33,10 +33,20 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.TypedValue;
+import android.util.TypedXmlPullParser;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -51,6 +61,8 @@ import java.util.regex.Pattern;
final class OverlayManagerShellCommand extends ShellCommand {
private final Context mContext;
private final IOverlayManager mInterface;
+ private static final Map<String, Integer> TYPE_MAP = Map.of(
+ "color", TypedValue.TYPE_FIRST_COLOR_INT);
OverlayManagerShellCommand(@NonNull final Context ctx, @NonNull final IOverlayManager iom) {
mContext = ctx;
@@ -126,7 +138,8 @@ final class OverlayManagerShellCommand extends ShellCommand {
out.println(" applying the current configuration and enabled overlays.");
out.println(" For a more fine-grained alternative, use 'idmap2 lookup'.");
out.println(" fabricate [--user USER_ID] [--target-name OVERLAYABLE] --target PACKAGE");
- out.println(" --name NAME PACKAGE:TYPE/NAME ENCODED-TYPE-ID ENCODED-VALUE");
+ out.println(" --name NAME [--file FILE] ");
+ out.println(" PACKAGE:TYPE/NAME ENCODED-TYPE-ID/TYPE-NAME ENCODED-VALUE");
out.println(" Create an overlay from a single resource. Caller must be root. Example:");
out.println(" fabricate --target android --name LighterGray \\");
out.println(" android:color/lighter_gray 0x1c 0xffeeeeee");
@@ -241,6 +254,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
String targetPackage = "";
String targetOverlayable = "";
String name = "";
+ String filename = null;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
@@ -256,6 +270,9 @@ final class OverlayManagerShellCommand extends ShellCommand {
case "--name":
name = getNextArgRequired();
break;
+ case "--file":
+ filename = getNextArgRequired();
+ break;
default:
err.println("Error: Unknown option: " + opt);
return 1;
@@ -271,42 +288,117 @@ final class OverlayManagerShellCommand extends ShellCommand {
err.println("Error: Missing required arg '--target'");
return 1;
}
-
- final String resourceName = getNextArgRequired();
- final String typeStr = getNextArgRequired();
- final int type;
- if (typeStr.startsWith("0x")) {
- type = Integer.parseUnsignedInt(typeStr.substring(2), 16);
- } else {
- type = Integer.parseUnsignedInt(typeStr);
- }
- final String dataStr = getNextArgRequired();
- final int data;
- if (dataStr.startsWith("0x")) {
- data = Integer.parseUnsignedInt(dataStr.substring(2), 16);
- } else {
- data = Integer.parseUnsignedInt(dataStr);
- }
-
- final PackageManager pm = mContext.getPackageManager();
- if (pm == null) {
- err.println("Error: failed to get package manager");
+ if (filename != null && getRemainingArgsCount() > 0) {
+ err.println(
+ "Error: When passing --file don't pass resource name, type, and value as well");
return 1;
}
-
final String overlayPackageName = "com.android.shell";
- final FabricatedOverlay overlay = new FabricatedOverlay.Builder(
+ FabricatedOverlay.Builder overlayBuilder = new FabricatedOverlay.Builder(
overlayPackageName, name, targetPackage)
- .setTargetOverlayable(targetOverlayable)
- .setResourceValue(resourceName, type, data)
- .build();
+ .setTargetOverlayable(targetOverlayable);
+ if (filename != null) {
+ int result = addOverlayValuesFromXml(overlayBuilder, targetPackage, filename);
+ if (result != 0) {
+ return result;
+ }
+ } else {
+ final String resourceName = getNextArgRequired();
+ final String typeStr = getNextArgRequired();
+ final String strData = getNextArgRequired();
+ addOverlayValue(overlayBuilder, resourceName, typeStr, strData);
+ }
mInterface.commit(new OverlayManagerTransaction.Builder()
- .registerFabricatedOverlay(overlay)
- .build());
+ .registerFabricatedOverlay(overlayBuilder.build()).build());
+ return 0;
+ }
+
+ private int addOverlayValuesFromXml(
+ FabricatedOverlay.Builder overlayBuilder, String targetPackage, String filename) {
+ final PrintWriter err = getErrPrintWriter();
+ File file = new File(filename);
+ if (!file.exists()) {
+ err.println("Error: File does not exist");
+ return 1;
+ }
+ if (!file.canRead()) {
+ err.println("Error: File is unreadable");
+ return 1;
+ }
+ try (FileInputStream fis = new FileInputStream(file)) {
+ TypedXmlPullParser parser = Xml.resolvePullParser(fis);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ continue;
+ }
+ parser.require(XmlPullParser.START_TAG, null, "overlay");
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (!tagName.equals("item")) {
+ err.println(TextUtils.formatSimple("Error: Unexpected tag: %s at line %d",
+ tagName, parser.getLineNumber()));
+ } else if (!parser.isEmptyElementTag()) {
+ err.println("Error: item tag must be empty");
+ return 1;
+ } else {
+ String target = parser.getAttributeValue(null, "target");
+ if (TextUtils.isEmpty(target)) {
+ err.println(
+ "Error: target name missing at line " + parser.getLineNumber());
+ return 1;
+ }
+ int index = target.indexOf('/');
+ if (index < 0) {
+ err.println("Error: target malformed, missing '/' at line "
+ + parser.getLineNumber());
+ return 1;
+ }
+ String overlayType = target.substring(0, index);
+ String value = parser.getAttributeValue(null, "value");
+ if (TextUtils.isEmpty(value)) {
+ err.println("Error: value missing at line " + parser.getLineNumber());
+ return 1;
+ }
+ addOverlayValue(overlayBuilder, targetPackage + ':' + target,
+ overlayType, value);
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return 1;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ return 1;
+ }
return 0;
}
+ private void addOverlayValue(FabricatedOverlay.Builder overlayBuilder,
+ String resourceName, String typeString, String valueString) {
+ final int type;
+ typeString = typeString.toLowerCase(Locale.getDefault());
+ if (TYPE_MAP.containsKey(typeString)) {
+ type = TYPE_MAP.get(typeString);
+ } else {
+ if (typeString.startsWith("0x")) {
+ type = Integer.parseUnsignedInt(typeString.substring(2), 16);
+ } else {
+ type = Integer.parseUnsignedInt(typeString);
+ }
+ }
+ final int intData;
+ if (valueString.startsWith("0x")) {
+ intData = Integer.parseUnsignedInt(valueString.substring(2), 16);
+ } else {
+ intData = Integer.parseUnsignedInt(valueString);
+ }
+ overlayBuilder.setResourceValue(resourceName, type, intData);
+ }
+
private int runEnableExclusive() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 1a6155b43f6b..01ddc482c123 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -16,8 +16,6 @@
package com.android.server.pm;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,7 +25,6 @@ import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.CompressedApexInfoList;
import android.apex.IApexService;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
@@ -42,7 +39,6 @@ import android.sysprop.ApexProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.PrintWriterPrinter;
import android.util.Singleton;
import android.util.Slog;
import android.util.SparseArray;
@@ -53,12 +49,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.build.UnboundedSdkLevel;
-import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.component.ParsedApexSystemService;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.TimingsTraceAndSlog;
import com.google.android.collect.Lists;
@@ -70,12 +62,10 @@ import java.lang.annotation.RetentionPolicy;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.ExecutorService;
/**
* ApexManager class handles communications with the apex service to perform operation and queries,
@@ -88,8 +78,6 @@ public abstract class ApexManager {
public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
- private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
-
private static final Singleton<ApexManager> sApexManagerSingleton =
new Singleton<ApexManager>() {
@Override
@@ -112,6 +100,17 @@ public abstract class ApexManager {
return sApexManagerSingleton.get();
}
+ static class ScanResult {
+ public final ApexInfo apexInfo;
+ public final AndroidPackage pkg;
+ public final String packageName;
+ ScanResult(ApexInfo apexInfo, AndroidPackage pkg, String packageName) {
+ this.apexInfo = apexInfo;
+ this.pkg = pkg;
+ this.packageName = packageName;
+ }
+ }
+
/**
* Minimal information about APEX mount points and the original APEX package they refer to.
* @hide
@@ -120,18 +119,21 @@ public abstract class ApexManager {
@Nullable public final String apexModuleName;
public final File apexDirectory;
public final File preInstalledApexPath;
+ public final boolean isFactory;
public final File apexFile;
public final boolean activeApexChanged;
private ActiveApexInfo(File apexDirectory, File preInstalledApexPath, File apexFile) {
- this(null, apexDirectory, preInstalledApexPath, apexFile, false);
+ this(null, apexDirectory, preInstalledApexPath, true, apexFile, false);
}
private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
- File preInstalledApexPath, File apexFile, boolean activeApexChanged) {
+ File preInstalledApexPath, boolean isFactory, File apexFile,
+ boolean activeApexChanged) {
this.apexModuleName = apexModuleName;
this.apexDirectory = apexDirectory;
this.preInstalledApexPath = preInstalledApexPath;
+ this.isFactory = isFactory;
this.apexFile = apexFile;
this.activeApexChanged = activeApexChanged;
}
@@ -142,11 +144,15 @@ public abstract class ApexManager {
new File(Environment.getApexDirectory() + File.separator
+ apexInfo.moduleName),
new File(apexInfo.preinstalledModulePath),
+ apexInfo.isFactory,
new File(apexInfo.modulePath),
apexInfo.activeApexChanged);
}
}
+ abstract ApexInfo[] getAllApexInfos();
+ abstract void notifyScanResult(List<ScanResult> scanResults);
+
/**
* Returns {@link ActiveApexInfo} records relative to all active APEX packages.
*
@@ -155,73 +161,6 @@ public abstract class ApexManager {
public abstract List<ActiveApexInfo> getActiveApexInfos();
/**
- * Called by package manager service to scan apex package files when device boots up.
- *
- * @param packageParser The package parser to support apex package parsing and caching parsed
- * results.
- * @param executorService An executor to support parallel package parsing.
- */
- abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
- @NonNull ExecutorService executorService);
-
- /**
- * Retrieves information about an APEX package.
- *
- * @param packageName the package name to look for. Note that this is the package name reported
- * in the APK container manifest (i.e. AndroidManifest.xml), which might
- * differ from the one reported in the APEX manifest (i.e.
- * apex_manifest.json).
- * @param flags the type of package to return. This may match to active packages
- * and factory (pre-installed) packages.
- * @return a PackageInfo object with the information about the package, or null if the package
- * is not found.
- */
- @Nullable
- public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
-
- /**
- * Retrieves information about all active APEX packages.
- *
- * @return a List of PackageInfo object, each one containing information about a different
- * active package.
- */
- abstract List<PackageInfo> getActivePackages();
-
- /**
- * Retrieves information about all active pre-installed APEX packages.
- *
- * @return a List of PackageInfo object, each one containing information about a different
- * active pre-installed package.
- */
- abstract List<PackageInfo> getFactoryPackages();
-
- /**
- * Retrieves information about all inactive APEX packages.
- *
- * @return a List of PackageInfo object, each one containing information about a different
- * inactive package.
- */
- abstract List<PackageInfo> getInactivePackages();
-
- /**
- * Checks if {@code packageName} is an apex package.
- *
- * @param packageName package to check.
- * @return {@code true} if {@code packageName} is an apex package.
- */
- abstract boolean isApexPackage(String packageName);
-
- /**
- * Whether the APEX package is pre-installed or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is pre-installed, {@code false} otherwise.
- */
- public static boolean isFactory(@NonNull PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- }
-
- /**
* Returns the active apex package's name that contains the (apk) package.
*
* @param containedPackageName The (apk) package that might be in a apex
@@ -423,9 +362,10 @@ public abstract class ApexManager {
/**
* Performs a non-staged install of the given {@code apexFile}.
+ *
+ * @return {@code ApeInfo} about the newly installed APEX package.
*/
- abstract void installPackage(File apexFile, PackageParser2 packageParser)
- throws PackageManagerException;
+ abstract ApexInfo installPackage(File apexFile) throws PackageManagerException;
/**
* Get a list of apex system services implemented in an apex.
@@ -447,10 +387,8 @@ public abstract class ApexManager {
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
- * information about that specific package will be dumped.
*/
- abstract void dump(PrintWriter pw, @Nullable String packageName);
+ abstract void dump(PrintWriter pw);
@IntDef(
flag = true,
@@ -492,9 +430,6 @@ public abstract class ApexManager {
@GuardedBy("mLock")
private Map<String, String> mErrorWithApkInApex = new ArrayMap<>();
- @GuardedBy("mLock")
- private List<PackageInfo> mAllPackagesCache;
-
/**
* An APEX is a file format that delivers the apex-payload wrapped in an apk container. The
* apk container has a reference name, called {@code packageName}, which is found inside the
@@ -514,16 +449,6 @@ public abstract class ApexManager {
private ArrayMap<String, String> mApexModuleNameToActivePackageName;
/**
- * Whether an APEX package is active or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is active, {@code false} otherwise.
- */
- private static boolean isActive(PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
- }
-
- /**
* Retrieve the service from ServiceManager. If the service is not running, it will be
* started, and this function will block until it is ready.
*/
@@ -535,252 +460,101 @@ public abstract class ApexManager {
}
@Override
- public List<ActiveApexInfo> getActiveApexInfos() {
- final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
- Trace.TRACE_TAG_PACKAGE_MANAGER);
- synchronized (mLock) {
- if (mActiveApexInfosCache == null) {
- t.traceBegin("getActiveApexInfos_noCache");
- try {
- mActiveApexInfosCache = new ArraySet<>();
- final ApexInfo[] activePackages = waitForApexService().getActivePackages();
- for (int i = 0; i < activePackages.length; i++) {
- ApexInfo apexInfo = activePackages[i];
- mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
- }
- t.traceEnd();
- }
- if (mActiveApexInfosCache != null) {
- return new ArrayList<>(mActiveApexInfosCache);
- } else {
- return Collections.emptyList();
- }
- }
- }
-
- @Override
- void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
- @NonNull ExecutorService executorService) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced");
- try {
- synchronized (mLock) {
- scanApexPackagesInternalLocked(packageParser, executorService);
- }
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- @GuardedBy("mLock")
- private void scanApexPackagesInternalLocked(PackageParser2 packageParser,
- ExecutorService executorService) {
- final ApexInfo[] allPkgs;
+ ApexInfo[] getAllApexInfos() {
try {
- mAllPackagesCache = new ArrayList<>();
- mPackageNameToApexModuleName = new ArrayMap<>();
- mApexModuleNameToActivePackageName = new ArrayMap<>();
- allPkgs = waitForApexService().getAllPackages();
+ return waitForApexService().getAllPackages();
} catch (RemoteException re) {
Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
throw new RuntimeException(re);
}
- if (allPkgs.length == 0) {
- return;
- }
- final int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
- ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
- ParallelPackageParser parallelPackageParser =
- new ParallelPackageParser(packageParser, executorService);
-
- for (ApexInfo ai : allPkgs) {
- File apexFile = new File(ai.modulePath);
- parallelPackageParser.submit(apexFile,
- ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
- parsingApexInfo.put(apexFile, ai);
- }
-
- HashSet<String> activePackagesSet = new HashSet<>();
- HashSet<String> factoryPackagesSet = new HashSet<>();
- // Process results one by one
- for (int i = 0; i < parsingApexInfo.size(); i++) {
- ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
- Throwable throwable = parseResult.throwable;
- ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
-
- if (throwable == null) {
- // Calling hideAsFinal to assign derived fields for the app info flags.
- parseResult.parsedPackage.hideAsFinal();
- final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
- parseResult.parsedPackage, ai, flags);
- if (packageInfo == null) {
- throw new IllegalStateException("Unable to generate package info: "
- + ai.modulePath);
- }
- mAllPackagesCache.add(packageInfo);
- for (ParsedApexSystemService service :
- parseResult.parsedPackage.getApexSystemServices()) {
- String minSdkVersion = service.getMinSdkVersion();
- if (minSdkVersion != null && !UnboundedSdkLevel.isAtLeast(minSdkVersion)) {
- Slog.d(TAG, String.format(
- "ApexSystemService %s with min_sdk_version=%s is skipped",
- service.getName(), service.getMinSdkVersion()));
- continue;
- }
- String maxSdkVersion = service.getMaxSdkVersion();
- if (maxSdkVersion != null && !UnboundedSdkLevel.isAtMost(maxSdkVersion)) {
- Slog.d(TAG, String.format(
- "ApexSystemService %s with max_sdk_version=%s is skipped",
- service.getName(), service.getMaxSdkVersion()));
- continue;
- }
-
- if (ai.isActive) {
- String name = service.getName();
- for (int j = 0; j < mApexSystemServices.size(); j++) {
- ApexSystemServiceInfo info = mApexSystemServices.get(j);
- if (info.getName().equals(name)) {
- throw new IllegalStateException(TextUtils.formatSimple(
- "Duplicate apex-system-service %s from %s, %s", name,
- info.mJarPath, service.getJarPath()));
- }
- }
- ApexSystemServiceInfo info = new ApexSystemServiceInfo(
- service.getName(), service.getJarPath(),
- service.getInitOrder());
- mApexSystemServices.add(info);
- }
- }
- Collections.sort(mApexSystemServices);
- mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
- if (ai.isActive) {
- if (activePackagesSet.contains(packageInfo.packageName)) {
- throw new IllegalStateException(
- "Two active packages have the same name: "
- + packageInfo.packageName);
- }
- activePackagesSet.add(packageInfo.packageName);
- if (mApexModuleNameToActivePackageName.containsKey(ai.moduleName)) {
- throw new IllegalStateException(
- "Two active packages have the same APEX module name: "
- + ai.moduleName);
- }
- mApexModuleNameToActivePackageName.put(
- ai.moduleName, packageInfo.packageName);
- }
- if (ai.isFactory) {
- // Don't throw when the duplicating APEX is VNDK APEX
- if (factoryPackagesSet.contains(packageInfo.packageName)
- && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
- throw new IllegalStateException(
- "Two factory packages have the same name: "
- + packageInfo.packageName);
- }
- factoryPackagesSet.add(packageInfo.packageName);
- }
- } else if (throwable instanceof PackageManagerException) {
- final PackageManagerException e = (PackageManagerException) throwable;
- // Skip parsing non-coreApp apex file if system is in minimal boot state.
- if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) {
- Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath);
- continue;
- }
- throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
- } else {
- throw new IllegalStateException("Unexpected exception occurred while parsing "
- + ai.modulePath, throwable);
- }
- }
}
@Override
- @Nullable
- public PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
+ void notifyScanResult(List<ScanResult> scanResults) {
synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
- boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!packageInfo.packageName.equals(packageName)) {
- continue;
- }
- if ((matchActive && isActive(packageInfo))
- || (matchFactory && isFactory(packageInfo))) {
- return packageInfo;
- }
- }
- return null;
+ notifyScanResultLocked(scanResults);
}
}
- @Override
- List<PackageInfo> getActivePackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> activePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isActive(packageInfo)) {
- activePackages.add(packageInfo);
+ @GuardedBy("mLock")
+ private void notifyScanResultLocked(List<ScanResult> scanResults) {
+ mPackageNameToApexModuleName = new ArrayMap<>();
+ mApexModuleNameToActivePackageName = new ArrayMap<>();
+ for (ScanResult scanResult : scanResults) {
+ ApexInfo ai = scanResult.apexInfo;
+ String packageName = scanResult.packageName;
+ for (ParsedApexSystemService service :
+ scanResult.pkg.getApexSystemServices()) {
+ String minSdkVersion = service.getMinSdkVersion();
+ if (minSdkVersion != null && !UnboundedSdkLevel.isAtLeast(minSdkVersion)) {
+ Slog.d(TAG, String.format(
+ "ApexSystemService %s with min_sdk_version=%s is skipped",
+ service.getName(), service.getMinSdkVersion()));
+ continue;
+ }
+ String maxSdkVersion = service.getMaxSdkVersion();
+ if (maxSdkVersion != null && !UnboundedSdkLevel.isAtMost(maxSdkVersion)) {
+ Slog.d(TAG, String.format(
+ "ApexSystemService %s with max_sdk_version=%s is skipped",
+ service.getName(), service.getMaxSdkVersion()));
+ continue;
}
- }
- return activePackages;
- }
- }
- @Override
- List<PackageInfo> getFactoryPackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> factoryPackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isFactory(packageInfo)) {
- factoryPackages.add(packageInfo);
+ if (ai.isActive) {
+ String name = service.getName();
+ for (int j = 0; j < mApexSystemServices.size(); j++) {
+ ApexSystemServiceInfo info = mApexSystemServices.get(j);
+ if (info.getName().equals(name)) {
+ throw new IllegalStateException(TextUtils.formatSimple(
+ "Duplicate apex-system-service %s from %s, %s", name,
+ info.mJarPath, service.getJarPath()));
+ }
+ }
+ ApexSystemServiceInfo info = new ApexSystemServiceInfo(
+ service.getName(), service.getJarPath(),
+ service.getInitOrder());
+ mApexSystemServices.add(info);
}
}
- return factoryPackages;
- }
- }
-
- @Override
- List<PackageInfo> getInactivePackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> inactivePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!isActive(packageInfo)) {
- inactivePackages.add(packageInfo);
+ Collections.sort(mApexSystemServices);
+ mPackageNameToApexModuleName.put(packageName, ai.moduleName);
+ if (ai.isActive) {
+ if (mApexModuleNameToActivePackageName.containsKey(ai.moduleName)) {
+ throw new IllegalStateException(
+ "Two active packages have the same APEX module name: "
+ + ai.moduleName);
}
+ mApexModuleNameToActivePackageName.put(
+ ai.moduleName, packageName);
}
- return inactivePackages;
}
}
@Override
- boolean isApexPackage(String packageName) {
- if (!isApexSupported()) return false;
+ public List<ActiveApexInfo> getActiveApexInfos() {
+ final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
+ Trace.TRACE_TAG_PACKAGE_MANAGER);
synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (packageInfo.packageName.equals(packageName)) {
- return true;
+ if (mActiveApexInfosCache == null) {
+ t.traceBegin("getActiveApexInfos_noCache");
+ try {
+ mActiveApexInfosCache = new ArraySet<>();
+ final ApexInfo[] activePackages = waitForApexService().getActivePackages();
+ for (int i = 0; i < activePackages.length; i++) {
+ ApexInfo apexInfo = activePackages[i];
+ mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
}
+ t.traceEnd();
+ }
+ if (mActiveApexInfosCache != null) {
+ return new ArrayList<>(mActiveApexInfosCache);
+ } else {
+ return Collections.emptyList();
}
}
- return false;
}
@Override
@@ -1136,55 +910,13 @@ public abstract class ApexManager {
}
@Override
- void installPackage(File apexFile, PackageParser2 packageParser)
+ ApexInfo installPackage(File apexFile)
throws PackageManagerException {
try {
- final int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
- final ParsedPackage parsedPackage = packageParser.parsePackage(
- apexFile, flags, /* useCaches= */ false);
- final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(parsedPackage,
- /* apexInfo= */ null, flags);
- if (newApexPkg == null) {
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Failed to generate package info for " + apexFile.getAbsolutePath());
- }
- final PackageInfo existingApexPkg = getPackageInfo(newApexPkg.packageName,
- MATCH_ACTIVE_PACKAGE);
- if (existingApexPkg == null) {
- Slog.w(TAG, "Attempting to install new APEX package " + newApexPkg.packageName);
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED,
- "It is forbidden to install new APEX packages");
- }
- checkApexSignature(existingApexPkg, newApexPkg);
- ApexInfo apexInfo = waitForApexService().installAndActivatePackage(
- apexFile.getAbsolutePath());
- final ParsedPackage parsedPackage2 = packageParser.parsePackage(
- new File(apexInfo.modulePath), flags, /* useCaches= */ false);
- final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
- parsedPackage2, apexInfo, flags);
- // Installation was successful, time to update mAllPackagesCache
- synchronized (mLock) {
- if (isFactory(existingApexPkg)) {
- existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
- mAllPackagesCache.add(finalApexPkg);
- } else {
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
- mAllPackagesCache.set(i, finalApexPkg);
- break;
- }
- }
- }
- }
+ return waitForApexService().installAndActivatePackage(apexFile.getAbsolutePath());
} catch (RemoteException e) {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"apexservice not available");
- } catch (PackageManagerException e) {
- // Catching it in order not to fall back to Exception which rethrows the
- // PackageManagerException with a common error code.
- throw e;
} catch (Exception e) {
// TODO(b/187864524): is INSTALL_FAILED_INTERNAL_ERROR is the right error code here?
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
@@ -1220,42 +952,8 @@ public abstract class ApexManager {
return null;
}
- /**
- * Dump information about the packages contained in a particular cache
- * @param packagesCache the cache to print information about.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set,
- * only information about that specific package will be dumped.
- * @param ipw the {@link IndentingPrintWriter} object to send information to.
- */
- void dumpFromPackagesCache(
- List<PackageInfo> packagesCache,
- @Nullable String packageName,
- IndentingPrintWriter ipw) {
- ipw.println();
- ipw.increaseIndent();
- for (int i = 0, size = packagesCache.size(); i < size; i++) {
- final PackageInfo pi = packagesCache.get(i);
- if (packageName != null && !packageName.equals(pi.packageName)) {
- continue;
- }
- ipw.println(pi.packageName);
- ipw.increaseIndent();
- ipw.println("Version: " + pi.versionCode);
- ipw.println("Path: " + pi.applicationInfo.sourceDir);
- ipw.println("IsActive: " + isActive(pi));
- ipw.println("IsFactory: " + isFactory(pi));
- ipw.println("ApplicationInfo: ");
- ipw.increaseIndent();
- pi.applicationInfo.dump(new PrintWriterPrinter(ipw), "");
- ipw.decreaseIndent();
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
- ipw.println();
- }
-
@Override
- void dump(PrintWriter pw, @Nullable String packageName) {
+ void dump(PrintWriter pw) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
try {
ipw.println();
@@ -1288,18 +986,6 @@ public abstract class ApexManager {
}
ipw.decreaseIndent();
ipw.println();
- synchronized (mLock) {
- if (mAllPackagesCache == null) {
- ipw.println("APEX packages have not been scanned");
- return;
- }
- }
- ipw.println("Active APEX packages:");
- dumpFromPackagesCache(getActivePackages(), packageName, ipw);
- ipw.println("Inactive APEX packages:");
- dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
- ipw.println("Factory APEX packages:");
- dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
} catch (RemoteException e) {
ipw.println("Couldn't communicate with apexd.");
}
@@ -1313,6 +999,16 @@ public abstract class ApexManager {
@VisibleForTesting
static final class ApexManagerFlattenedApex extends ApexManager {
@Override
+ ApexInfo[] getAllApexInfos() {
+ return null;
+ }
+
+ @Override
+ void notifyScanResult(List<ScanResult> scanResults) {
+ // No-op
+ }
+
+ @Override
public List<ActiveApexInfo> getActiveApexInfos() {
// There is no apexd running in case of flattened apex
// We look up the /apex directory and identify the active APEX modules from there.
@@ -1340,37 +1036,6 @@ public abstract class ApexManager {
}
@Override
- void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
- @NonNull ExecutorService executorService) {
- // No-op
- }
-
- @Override
- public PackageInfo getPackageInfo(String packageName, int flags) {
- return null;
- }
-
- @Override
- List<PackageInfo> getActivePackages() {
- return Collections.emptyList();
- }
-
- @Override
- List<PackageInfo> getFactoryPackages() {
- return Collections.emptyList();
- }
-
- @Override
- List<PackageInfo> getInactivePackages() {
- return Collections.emptyList();
- }
-
- @Override
- boolean isApexPackage(String packageName) {
- return false;
- }
-
- @Override
@Nullable
public String getActiveApexPackageNameContainingPackage(
@NonNull String containedPackageName) {
@@ -1505,7 +1170,7 @@ public abstract class ApexManager {
}
@Override
- void installPackage(File apexFile, PackageParser2 packageParser) {
+ ApexInfo installPackage(File apexFile) {
throw new UnsupportedOperationException("APEX updates are not supported");
}
@@ -1517,13 +1182,12 @@ public abstract class ApexManager {
}
@Override
- public File getBackingApexFile(File file) {
- return null;
+ void dump(PrintWriter pw) {
}
@Override
- void dump(PrintWriter pw, String packageName) {
- // No-op
+ public File getBackingApexFile(File file) {
+ return null;
}
}
}
diff --git a/services/core/java/com/android/server/pm/ApexPackageInfo.java b/services/core/java/com/android/server/pm/ApexPackageInfo.java
new file mode 100644
index 000000000000..07f2fd3e1d1f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApexPackageInfo.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2022 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.pm;
+
+import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
+import static com.android.server.pm.ApexManager.MATCH_FACTORY_PACKAGE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.ArrayMap;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * A temporary holder to store PackageInfo for scanned apex packages. We will unify the scan/install
+ * flows of APK and APEX and PMS will be the only source of truth for all package information
+ * including both APK and APEX. This class will no longer be needed when the migration is done.
+ */
+class ApexPackageInfo {
+ public static final boolean ENABLE_FEATURE_SCAN_APEX = true;
+
+ private static final String TAG = "ApexManager";
+ private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private List<PackageInfo> mAllPackagesCache;
+
+ /**
+ * Whether an APEX package is active or not.
+ *
+ * @param packageInfo the package to check
+ * @return {@code true} if this package is active, {@code false} otherwise.
+ */
+ private static boolean isActive(PackageInfo packageInfo) {
+ return packageInfo.isActiveApex;
+ }
+
+ /**
+ * Called by package manager service to scan apex package files when device boots up.
+ *
+ * @param allPackages All apex packages to scan.
+ * @param packageParser The package parser to support apex package parsing and caching parsed
+ * results.
+ * @param executorService An executor to support parallel package parsing.
+ */
+ List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages,
+ @NonNull PackageParser2 packageParser, @NonNull ExecutorService executorService) {
+ synchronized (mLock) {
+ return scanApexPackagesInternalLocked(allPackages, packageParser, executorService);
+ }
+ }
+
+ void notifyScanResult(List<ApexManager.ScanResult> scanResults) {
+ synchronized (mLock) {
+ notifyScanResultLocked(scanResults);
+ }
+ }
+
+ /**
+ * Retrieves information about an APEX package.
+ *
+ * @param packageName the package name to look for. Note that this is the package name reported
+ * in the APK container manifest (i.e. AndroidManifest.xml), which might
+ * differ from the one reported in the APEX manifest (i.e.
+ * apex_manifest.json).
+ * @param flags the type of package to return. This may match to active packages
+ * and factory (pre-installed) packages.
+ * @return a PackageInfo object with the information about the package, or null if the package
+ * is not found.
+ */
+ @Nullable
+ PackageInfo getPackageInfo(String packageName, @ApexManager.PackageInfoFlags int flags) {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
+ boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (!packageInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if ((matchActive && isActive(packageInfo))
+ || (matchFactory && isFactory(packageInfo))) {
+ return packageInfo;
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Retrieves information about all active APEX packages.
+ *
+ * @return a List of PackageInfo object, each one containing information about a different
+ * active package.
+ */
+ List<PackageInfo> getActivePackages() {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> activePackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (isActive(packageInfo)) {
+ activePackages.add(packageInfo);
+ }
+ }
+ return activePackages;
+ }
+ }
+
+ /**
+ * Retrieves information about all active pre-installed APEX packages.
+ *
+ * @return a List of PackageInfo object, each one containing information about a different
+ * active pre-installed package.
+ */
+ List<PackageInfo> getFactoryPackages() {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> factoryPackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (isFactory(packageInfo)) {
+ factoryPackages.add(packageInfo);
+ }
+ }
+ return factoryPackages;
+ }
+ }
+
+ /**
+ * Retrieves information about all inactive APEX packages.
+ *
+ * @return a List of PackageInfo object, each one containing information about a different
+ * inactive package.
+ */
+ List<PackageInfo> getInactivePackages() {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> inactivePackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (!isActive(packageInfo)) {
+ inactivePackages.add(packageInfo);
+ }
+ }
+ return inactivePackages;
+ }
+ }
+
+ /**
+ * Checks if {@code packageName} is an apex package.
+ *
+ * @param packageName package to check.
+ * @return {@code true} if {@code packageName} is an apex package.
+ */
+ boolean isApexPackage(String packageName) {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (packageInfo.packageName.equals(packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called to update cached PackageInfo when installing rebootless APEX.
+ */
+ void notifyPackageInstalled(ApexInfo apexInfo, PackageParser2 packageParser)
+ throws PackageManagerException {
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_SIGNATURES;
+ final ParsedPackage parsedPackage = packageParser.parsePackage(
+ new File(apexInfo.modulePath), flags, /* useCaches= */ false);
+ notifyPackageInstalled(apexInfo, parsedPackage.hideAsFinal());
+ }
+
+ void notifyPackageInstalled(ApexInfo apexInfo, AndroidPackage pkg) {
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_SIGNATURES;
+ final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(
+ pkg, apexInfo, flags);
+ final String packageName = newApexPkg.packageName;
+ synchronized (mLock) {
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ PackageInfo oldApexPkg = mAllPackagesCache.get(i);
+ if (oldApexPkg.isActiveApex && oldApexPkg.packageName.equals(packageName)) {
+ if (isFactory(oldApexPkg)) {
+ oldApexPkg.isActiveApex = false;
+ mAllPackagesCache.add(newApexPkg);
+ } else {
+ mAllPackagesCache.set(i, newApexPkg);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Whether the APEX package is pre-installed or not.
+ *
+ * @param packageInfo the package to check
+ * @return {@code true} if this package is pre-installed, {@code false} otherwise.
+ */
+ private static boolean isFactory(@NonNull PackageInfo packageInfo) {
+ return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0;
+ }
+
+ /**
+ * Dumps various state information to the provided {@link PrintWriter} object.
+ *
+ * @param pw the {@link PrintWriter} object to send information to.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
+ * information about that specific package will be dumped.
+ */
+ void dump(PrintWriter pw, @Nullable String packageName) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ synchronized (mLock) {
+ if (mAllPackagesCache == null) {
+ ipw.println("APEX packages have not been scanned");
+ return;
+ }
+ }
+ ipw.println("Active APEX packages:");
+ dumpFromPackagesCache(getActivePackages(), packageName, ipw);
+ ipw.println("Inactive APEX packages:");
+ dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
+ ipw.println("Factory APEX packages:");
+ dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
+ }
+
+ @GuardedBy("mLock")
+ private void notifyScanResultLocked(List<ApexManager.ScanResult> scanResults) {
+ mAllPackagesCache = new ArrayList<>();
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_SIGNATURES;
+
+ HashSet<String> activePackagesSet = new HashSet<>();
+ HashSet<String> factoryPackagesSet = new HashSet<>();
+ for (ApexManager.ScanResult result : scanResults) {
+ ApexInfo ai = result.apexInfo;
+
+ final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
+ result.pkg, ai, flags);
+ if (packageInfo == null) {
+ throw new IllegalStateException("Unable to generate package info: "
+ + ai.modulePath);
+ }
+ if (!packageInfo.packageName.equals(result.packageName)) {
+ throw new IllegalStateException("Unmatched package name: "
+ + result.packageName + " != " + packageInfo.packageName
+ + ", path=" + ai.modulePath);
+ }
+ mAllPackagesCache.add(packageInfo);
+ if (ai.isActive) {
+ if (!activePackagesSet.add(packageInfo.packageName)) {
+ throw new IllegalStateException(
+ "Two active packages have the same name: "
+ + packageInfo.packageName);
+ }
+ }
+ if (ai.isFactory) {
+ // Don't throw when the duplicating APEX is VNDK APEX
+ if (!factoryPackagesSet.add(packageInfo.packageName)
+ && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
+ throw new IllegalStateException(
+ "Two factory packages have the same name: "
+ + packageInfo.packageName);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private List<ApexManager.ScanResult> scanApexPackagesInternalLocked(final ApexInfo[] allPkgs,
+ PackageParser2 packageParser, ExecutorService executorService) {
+ if (allPkgs == null || allPkgs.length == 0) {
+ notifyScanResultLocked(Collections.EMPTY_LIST);
+ return Collections.EMPTY_LIST;
+ }
+
+ ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
+ ParallelPackageParser parallelPackageParser =
+ new ParallelPackageParser(packageParser, executorService);
+ for (ApexInfo ai : allPkgs) {
+ File apexFile = new File(ai.modulePath);
+ parallelPackageParser.submit(apexFile,
+ ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
+ parsingApexInfo.put(apexFile, ai);
+ }
+
+ List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
+ // Process results one by one
+ for (int i = 0; i < parsingApexInfo.size(); i++) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
+
+ if (throwable == null) {
+ // Calling hideAsFinal to assign derived fields for the app info flags.
+ parseResult.parsedPackage.hideAsFinal();
+ results.add(new ApexManager.ScanResult(
+ ai, parseResult.parsedPackage, parseResult.parsedPackage.getPackageName()));
+ } else if (throwable instanceof PackageManagerException) {
+ throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + ai.modulePath, throwable);
+ }
+ }
+
+ notifyScanResultLocked(results);
+ return results;
+ }
+
+ /**
+ * Dump information about the packages contained in a particular cache
+ * @param packagesCache the cache to print information about.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set,
+ * only information about that specific package will be dumped.
+ * @param ipw the {@link IndentingPrintWriter} object to send information to.
+ */
+ private static void dumpFromPackagesCache(List<PackageInfo> packagesCache,
+ @Nullable String packageName, IndentingPrintWriter ipw) {
+ ipw.println();
+ ipw.increaseIndent();
+ for (int i = 0, size = packagesCache.size(); i < size; i++) {
+ final PackageInfo pi = packagesCache.get(i);
+ if (packageName != null && !packageName.equals(pi.packageName)) {
+ continue;
+ }
+ ipw.println(pi.packageName);
+ ipw.increaseIndent();
+ ipw.println("Version: " + pi.versionCode);
+ ipw.println("Path: " + pi.applicationInfo.sourceDir);
+ ipw.println("IsActive: " + isActive(pi));
+ ipw.println("IsFactory: " + isFactory(pi));
+ ipw.println("ApplicationInfo: ");
+ ipw.increaseIndent();
+ pi.applicationInfo.dump(new PrintWriterPrinter(ipw), "");
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ ipw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 66f71a37e0a3..ce323fc4d883 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -520,14 +520,13 @@ final class AppDataHelper {
int count = 0;
final Installer.Batch batch = new Installer.Batch();
for (String pkgName : deferPackages) {
- AndroidPackage pkg = null;
- synchronized (mPm.mLock) {
- PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
- if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
- pkg = ps.getPkg();
- }
- }
- if (pkg != null) {
+ final Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageStateInternal = snapshot.getPackageStateInternal(
+ pkgName);
+ if (packageStateInternal != null
+ && packageStateInternal.getUserStateOrDefault(
+ UserHandle.USER_SYSTEM).isInstalled()) {
+ AndroidPackage pkg = packageStateInternal.getPkg();
prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags,
true /* maybeMigrateAppData */);
count++;
@@ -554,12 +553,12 @@ final class AppDataHelper {
}
private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
- final PackageSetting ps;
- synchronized (mPm.mLock) {
- ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
- }
+ final Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageStateInternal =
+ snapshot.getPackageStateInternal(pkg.getPackageName());
for (int realUserId : mPm.resolveUserIds(userId)) {
- final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
+ final long ceDataInode = (packageStateInternal != null)
+ ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
try {
mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
flags, ceDataInode);
@@ -586,12 +585,12 @@ final class AppDataHelper {
}
public void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
- final PackageSetting ps;
- synchronized (mPm.mLock) {
- ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
- }
+ final Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageStateInternal =
+ snapshot.getPackageStateInternal(pkg.getPackageName());
for (int realUserId : mPm.resolveUserIds(userId)) {
- final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
+ final long ceDataInode = (packageStateInternal != null)
+ ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
try {
mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
flags, ceDataInode);
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 9d1f0704a3cf..2aec18778615 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -28,6 +28,7 @@ import android.Manifest;
import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.BroadcastOptions;
@@ -40,8 +41,10 @@ import android.content.pm.PackageInstaller;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerExemptionManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -49,6 +52,8 @@ import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Helper class to send broadcasts for various situations.
@@ -147,30 +152,40 @@ public final class BroadcastHelper {
}
}
- public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
- sendResourcesChangedBroadcast(mediaStatus, replacing,
- pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
- }
+ public void sendResourcesChangedBroadcast(@NonNull Computer snapshot, boolean mediaStatus,
+ boolean replacing, @NonNull String[] pkgNames, @NonNull int[] uids) {
+ if (ArrayUtils.isEmpty(pkgNames) || ArrayUtils.isEmpty(uids)) {
+ return;
+ }
- public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- String[] pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
- int size = pkgList.length;
- if (size > 0) {
- // Send broadcasts here
- Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- if (uidArr != null) {
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ return;
}
- if (replacing) {
- extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
+
+ final int[] resolvedUserIds = am.getRunningUserIds();
+ for (int userId : resolvedUserIds) {
+ final var lists = getBroadcastParams(snapshot, pkgNames, uids, userId);
+ for (int i = 0; i < lists.size(); i++) {
+ // Send broadcasts here
+ final Bundle extras = new Bundle(3);
+ final BroadcastParams list = lists.get(i);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
+ extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
+ final SparseArray<int[]> allowList = list.getAllowList().size() == 0
+ ? null : list.getAllowList();
+ final String action =
+ mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
+ sendPackageBroadcast(action, null /* pkg */, extras, 0 /* flags */,
+ null /* targetPkg */, null /* finishedReceiver */, new int[]{userId},
+ null /* instantUserIds */, allowList, null /* bOptions */);
+ }
}
- String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
- : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- // TODO: not sure how to handle this one.
- sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver,
- null, null, null, null);
+ } catch (RemoteException ex) {
}
}
@@ -327,4 +342,45 @@ public final class BroadcastHelper {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
}
+
+ /**
+ * Get broadcast params list based on the given package and uid list. The broadcast params are
+ * used to send broadcast separately if the given packages have different visibility allow list.
+ *
+ * @param pkgList The names of packages which have changes.
+ * @param uidList The uids of packages which have changes.
+ * @param userId The user where packages reside.
+ * @return The list of {@link BroadcastParams} object.
+ */
+ public List<BroadcastParams> getBroadcastParams(@NonNull Computer snapshot,
+ @NonNull String[] pkgList, @NonNull int[] uidList, @UserIdInt int userId) {
+ final List<BroadcastParams> lists = new ArrayList<>(pkgList.length);
+ // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if
+ // allow lists are the same.
+ for (int i = 0; i < pkgList.length; i++) {
+ final String pkgName = pkgList[i];
+ final int uid = uidList[i];
+ if (TextUtils.isEmpty(pkgName) || Process.INVALID_UID == uid) {
+ continue;
+ }
+ int[] allowList = snapshot.getVisibilityAllowList(pkgName, userId);
+ if (allowList == null) {
+ allowList = new int[0];
+ }
+ boolean merged = false;
+ for (int j = 0; j < lists.size(); j++) {
+ final BroadcastParams list = lists.get(j);
+ if (Arrays.equals(list.getAllowList().get(userId), allowList)) {
+ list.addPackage(pkgName, uid);
+ merged = true;
+ break;
+ }
+ }
+ if (!merged) {
+ lists.add(new BroadcastParams(pkgName, uid, allowList, userId));
+ }
+ }
+
+ return lists;
+ }
}
diff --git a/services/core/java/com/android/server/pm/BroadcastParams.java b/services/core/java/com/android/server/pm/BroadcastParams.java
new file mode 100644
index 000000000000..279aab040f7b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BroadcastParams.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.pm;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.util.IntArray;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A helper class that contains information about package names and uids that share the same allow
+ * list for sending broadcasts. Used by various package helpers.
+ */
+final class BroadcastParams {
+ private final @NonNull List<String> mPackageNames;
+ private final @NonNull IntArray mUids;
+ private final @NonNull SparseArray<int[]> mAllowList;
+
+ BroadcastParams(@NonNull String packageName, @IntRange(from = 0) int uid,
+ @NonNull int[] allowList, @UserIdInt int userId) {
+ mPackageNames = new ArrayList<>(Arrays.asList(packageName));
+ mUids = IntArray.wrap(new int[]{uid});
+ mAllowList = new SparseArray<>(1);
+ mAllowList.put(userId, allowList);
+ }
+
+ public void addPackage(@NonNull String packageName, @IntRange(from = 0) int uid) {
+ mPackageNames.add(packageName);
+ mUids.add(uid);
+ }
+
+ public @NonNull String[] getPackageNames() {
+ return mPackageNames.toArray(new String[0]);
+ }
+
+ public @NonNull int[] getUids() {
+ return mUids.toArray();
+ }
+
+ public @NonNull SparseArray<int[]> getAllowList() {
+ return mAllowList;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index eb635500580a..5a2f6feb4d83 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -220,11 +220,36 @@ public interface Computer extends PackageDataSnapshot {
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
@Nullable ComponentName component, @PackageManager.ComponentType int componentType,
+ int userId, boolean filterUninstall);
+ boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
+ @Nullable ComponentName component, @PackageManager.ComponentType int componentType,
int userId);
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
int userId);
boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
int userId);
+ /**
+ * Different form {@link #shouldFilterApplication(PackageStateInternal, int, int)}, the function
+ * returns {@code true} if the target package is not found in the device or uninstalled in the
+ * current user. Unless the caller's function needs to handle the package's uninstalled state
+ * by itself, using this function to keep the consistent behavior between conditions of package
+ * uninstalled and visibility not allowed to avoid the side channel leakage of package
+ * existence.
+ * <p>
+ * Package with {@link PackageManager#SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN} is not
+ * treated as an uninstalled package for the carrier apps customization.
+ */
+ boolean shouldFilterApplicationIncludingUninstalled(@Nullable PackageStateInternal ps,
+ int callingUid, int userId);
+ /**
+ * Different from {@link #shouldFilterApplication(SharedUserSetting, int, int)}, the function
+ * returns {@code true} if packages with the same shared user are all uninstalled in the current
+ * user.
+ *
+ * @see #shouldFilterApplicationIncludingUninstalled(PackageStateInternal, int, int)
+ */
+ boolean shouldFilterApplicationIncludingUninstalled(@NonNull SharedUserSetting sus,
+ int callingUid, int userId);
int checkUidPermission(String permName, int uid);
int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
long updateFlagsForApplication(long flags, int userId);
@@ -310,6 +335,8 @@ public interface Computer extends PackageDataSnapshot {
boolean isPackageAvailable(String packageName, @UserIdInt int userId);
+ boolean isApexPackage(String packageName);
+
@NonNull
String[] currentToCanonicalPackageNames(@NonNull String[] names);
@@ -322,8 +349,9 @@ public interface Computer extends PackageDataSnapshot {
int getTargetSdkVersion(@NonNull String packageName);
- boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType);
+ boolean activitySupportsIntentAsUser(@NonNull ComponentName resolveComponentName,
+ @NonNull ComponentName component, @NonNull Intent intent, String resolvedType,
+ int userId);
@Nullable
ActivityInfo getReceiverInfo(@NonNull ComponentName component,
@@ -360,17 +388,19 @@ public interface Computer extends PackageDataSnapshot {
String[] getSystemSharedLibraryNames();
/**
- * @return the state if the given package has a state and isn't filtered by visibility.
+ * @return the state if the given package is installed and isn't filtered by visibility.
* Provides no guarantee that the package is in any usable state.
*/
@Nullable
- PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId);
+ PackageStateInternal getPackageStateForInstalledAndFiltered(@NonNull String packageName,
+ int callingUid, @UserIdInt int userId);
- int checkSignatures(@NonNull String pkg1, @NonNull String pkg2);
+ int checkSignatures(@NonNull String pkg1, @NonNull String pkg2, int userId);
int checkUidSignatures(int uid1, int uid2);
+ int checkUidSignaturesForAllUsers(int uid1, int uid2);
+
boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
@@ -395,7 +425,7 @@ public interface Computer extends PackageDataSnapshot {
boolean isUidPrivileged(int uid);
@NonNull
- String[] getAppOpPermissionPackages(@NonNull String permissionName);
+ String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId);
@NonNull
ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,
@@ -422,11 +452,12 @@ public interface Computer extends PackageDataSnapshot {
@PackageManager.ComponentInfoFlagsBits long flags, @Nullable String metaDataKey);
@Nullable
- InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags);
+ InstrumentationInfo getInstrumentationInfoAsUser(@NonNull ComponentName component, int flags,
+ int userId);
@NonNull
- ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags);
+ ParceledListSlice<InstrumentationInfo> queryInstrumentationAsUser(
+ @NonNull String targetPackage, int flags, int userId);
@NonNull
List<PackageStateInternal> findSharedNonSystemLibraries(
@@ -444,10 +475,6 @@ public interface Computer extends PackageDataSnapshot {
boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId);
@Nullable
- SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName, @UserIdInt int[] userIds,
- boolean isInstantApp);
-
- @Nullable
String getInstallerPackageName(@NonNull String packageName);
@Nullable
@@ -483,6 +510,16 @@ public interface Computer extends PackageDataSnapshot {
boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks);
+ /**
+ * See {@link AppsFilterSnapshot#getVisibilityAllowList(PackageStateInternal, int[], ArrayMap)}
+ */
+ @Nullable
+ SparseArray<int[]> getVisibilityAllowLists(@NonNull String packageName,
+ @UserIdInt int[] userIds);
+
+ /**
+ * See {@link AppsFilterSnapshot#getVisibilityAllowList(PackageStateInternal, int[], ArrayMap)}
+ */
@Nullable
int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 30de9ba638cc..f01dbfeed735 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -399,6 +399,7 @@ public class ComputerEngine implements Computer {
private final UserManagerService mUserManager;
private final PermissionManagerServiceInternal mPermissionManager;
private final ApexManager mApexManager;
+ private final ApexPackageInfo mApexPackageInfo;
private final PackageManagerServiceInjector mInjector;
private final ComponentResolverApi mComponentResolver;
private final InstantAppResolverConnection mInstantAppResolverConnection;
@@ -453,6 +454,7 @@ public class ComputerEngine implements Computer {
mContext = args.service.mContext;
mInjector = args.service.mInjector;
mApexManager = args.service.mApexManager;
+ mApexPackageInfo = args.service.mApexPackageInfo;
mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
mDefaultAppProvider = args.service.getDefaultAppProvider();
mDomainVerificationManager = args.service.mDomainVerificationManager;
@@ -549,8 +551,13 @@ public class ComputerEngine implements Computer {
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
|| (matchVisibleToInstantAppOnly && isCallerInstantApp
&& isTargetHiddenFromInstantApp));
+ final boolean resolveForStartNonExported = resolveForStart
+ && !ai.exported
+ && !isCallerSameApp(pkgName, filterCallingUid);
final boolean blockNormalResolution =
- !resolveForStart && !isTargetInstantApp && !isCallerInstantApp
+ (!resolveForStart || resolveForStartNonExported)
+ && !isTargetInstantApp
+ && !isCallerInstantApp
&& shouldFilterApplication(
getPackageStateInternal(ai.applicationInfo.packageName,
Process.SYSTEM_UID), filterCallingUid, userId);
@@ -1003,7 +1010,7 @@ public class ComputerEngine implements Computer {
if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
}
- final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags);
+ final PackageInfo pi = mApexPackageInfo.getPackageInfo(packageName, apexFlags);
if (pi == null) {
return null;
}
@@ -1700,7 +1707,7 @@ public class ComputerEngine implements Computer {
if (matchFactoryOnly) {
// Instant app filtering for APEX modules is ignored
if ((flags & MATCH_APEX) != 0) {
- return mApexManager.getPackageInfo(packageName,
+ return mApexPackageInfo.getPackageInfo(packageName,
ApexManager.MATCH_FACTORY_PACKAGE);
}
final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName);
@@ -1745,7 +1752,7 @@ public class ComputerEngine implements Computer {
return generatePackageInfo(ps, flags, userId);
}
if ((flags & MATCH_APEX) != 0) {
- return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
+ return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
}
return null;
}
@@ -1841,12 +1848,9 @@ public class ComputerEngine implements Computer {
}
if (listApex) {
if (listFactory) {
- list.addAll(mApexManager.getFactoryPackages());
+ list.addAll(mApexPackageInfo.getFactoryPackages());
} else {
- list.addAll(mApexManager.getActivePackages());
- if (listUninstalled) {
- list.addAll(mApexManager.getInactivePackages());
- }
+ list.addAll(mApexPackageInfo.getActivePackages());
}
}
return new ParceledListSlice<>(list);
@@ -2682,7 +2686,7 @@ public class ComputerEngine implements Computer {
*/
public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
int callingUid, @Nullable ComponentName component,
- @PackageManager.ComponentType int componentType, int userId) {
+ @PackageManager.ComponentType int componentType, int userId, boolean filterUninstall) {
if (Process.isSdkSandboxUid(callingUid)) {
int clientAppUid = Process.getAppUidForSdkSandboxUid(callingUid);
// SDK sandbox should be able to see it's client app
@@ -2696,9 +2700,13 @@ public class ComputerEngine implements Computer {
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final boolean callerIsInstantApp = instantAppPkgName != null;
- if (ps == null) {
- // pretend the application exists, but, needs to be filtered
- return callerIsInstantApp;
+ // Don't treat hiddenUntilInstalled as an uninstalled state, phone app needs to access
+ // these hidden application details to customize carrier apps.
+ if (ps == null || (filterUninstall && !ps.isHiddenUntilInstalled()
+ && !ps.getUserStateOrDefault(userId).isInstalled())) {
+ // If caller is instant app and ps is null, pretend the application exists,
+ // but, needs to be filtered
+ return (callerIsInstantApp || filterUninstall);
}
// if the target and caller are the same application, don't filter
if (isCallerSameApp(ps.getPackageName(), callingUid)) {
@@ -2743,15 +2751,26 @@ public class ComputerEngine implements Computer {
}
/**
- * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+ */
+ public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
+ int callingUid, @Nullable ComponentName component,
+ @PackageManager.ComponentType int componentType, int userId) {
+ return shouldFilterApplication(
+ ps, callingUid, component, componentType, userId, false /* filterUninstall */);
+ }
+
+ /**
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
*/
public final boolean shouldFilterApplication(
@Nullable PackageStateInternal ps, int callingUid, int userId) {
- return shouldFilterApplication(ps, callingUid, null, TYPE_UNKNOWN, userId);
+ return shouldFilterApplication(
+ ps, callingUid, null, TYPE_UNKNOWN, userId, false /* filterUninstall */);
}
/**
- * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
*/
public final boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
int callingUid, int userId) {
@@ -2759,13 +2778,42 @@ public class ComputerEngine implements Computer {
final ArraySet<PackageStateInternal> packageStates =
(ArraySet<PackageStateInternal>) sus.getPackageStates();
for (int index = packageStates.size() - 1; index >= 0 && filterApp; index--) {
- filterApp &= shouldFilterApplication(packageStates.valueAt(index),
- callingUid, /* component */ null, TYPE_UNKNOWN, userId);
+ filterApp &= shouldFilterApplication(packageStates.valueAt(index), callingUid,
+ null /* component */, TYPE_UNKNOWN, userId, false /* filterUninstall */);
}
return filterApp;
}
/**
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+ */
+ public final boolean shouldFilterApplicationIncludingUninstalled(
+ @Nullable PackageStateInternal ps, int callingUid, int userId) {
+ return shouldFilterApplication(
+ ps, callingUid, null, TYPE_UNKNOWN, userId, true /* filterUninstall */);
+ }
+
+ /**
+ * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+ */
+ public final boolean shouldFilterApplicationIncludingUninstalled(
+ @NonNull SharedUserSetting sus, int callingUid, int userId) {
+ if (shouldFilterApplication(sus, callingUid, userId)) {
+ return true;
+ }
+ final ArraySet<PackageStateInternal> packageStates =
+ (ArraySet<PackageStateInternal>) sus.getPackageStates();
+ for (int index = 0; index < packageStates.size(); index++) {
+ final PackageStateInternal ps = packageStates.valueAt(index);
+ if (ps.getUserStateOrDefault(userId).isInstalled() || ps.isHiddenUntilInstalled()) {
+ return false;
+ }
+ }
+ // Filter it, all packages with the same shared uid are uninstalled.
+ return true;
+ }
+
+ /**
* Verification statuses are ordered from the worse to the best, except for
* INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
*/
@@ -3110,7 +3158,7 @@ public class ComputerEngine implements Computer {
final boolean checkin = dumpState.isCheckIn();
// Return if the package doesn't exist.
- if (packageName != null && setting == null) {
+ if (packageName != null && setting == null && !isApexPackage(packageName)) {
return;
}
@@ -3204,7 +3252,8 @@ public class ComputerEngine implements Computer {
for (PackageStateInternal pkgSetting : pkgSettings) {
final AndroidPackage pkg = pkgSetting.getPkg();
- if (pkg == null) {
+ if (pkg == null || pkg.isApex()) {
+ // Skip APEX which is not dex-optimized
continue;
}
final String pkgName = pkg.getPackageName();
@@ -3284,6 +3333,15 @@ public class ComputerEngine implements Computer {
}
}
ipw.decreaseIndent();
+ break;
+ }
+
+ case DumpState.DUMP_APEX: {
+ if (packageName == null || isApexPackage(packageName)) {
+ mApexManager.dump(pw);
+ mApexPackageInfo.dump(pw, packageName);
+ }
+ break;
}
} // switch
}
@@ -3663,6 +3721,11 @@ public class ComputerEngine implements Computer {
}
@Override
+ public boolean isApexPackage(String packageName) {
+ return mApexPackageInfo.isApexPackage(packageName);
+ }
+
+ @Override
public String[] currentToCanonicalPackageNames(String[] names) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
@@ -3751,7 +3814,7 @@ public class ComputerEngine implements Computer {
if (ps == null || ps.getPkg() == null) {
return -1;
}
- if (shouldFilterApplication(ps, Binder.getCallingUid(),
+ if (shouldFilterApplicationIncludingUninstalled(ps, Binder.getCallingUid(),
UserHandle.getCallingUserId())) {
return -1;
}
@@ -3759,14 +3822,16 @@ public class ComputerEngine implements Computer {
}
@Override
- public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
+ public boolean activitySupportsIntentAsUser(@NonNull ComponentName resolveComponentName,
+ @NonNull ComponentName component, @NonNull Intent intent, String resolvedType,
+ int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "activitySupportsIntentAsUser");
if (component.equals(resolveComponentName)) {
// The resolver supports EVERYTHING!
return true;
}
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
ParsedActivity a = mComponentResolver.getActivity(component);
if (a == null) {
return false;
@@ -3776,7 +3841,7 @@ public class ComputerEngine implements Computer {
return false;
}
if (shouldFilterApplication(
- ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
+ ps, callingUid, component, TYPE_ACTIVITY, userId, true /* filterUninstall */)) {
return false;
}
for (int i=0; i< a.getIntents().size(); i++) {
@@ -4176,17 +4241,22 @@ public class ComputerEngine implements Computer {
}
@Override
- public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
+ public PackageStateInternal getPackageStateForInstalledAndFiltered(@NonNull String packageName,
+ int callingUid, @UserIdInt int userId) {
final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null || shouldFilterApplication(packageState, callingUid, userId)) {
+ if (packageState == null
+ || shouldFilterApplicationIncludingUninstalled(packageState, callingUid, userId)) {
return null;
}
return packageState;
}
@Override
- public int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
+ public int checkSignatures(@NonNull String pkg1, @NonNull String pkg2, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "checkSignatures");
+
final AndroidPackage p1 = mPackages.get(pkg1);
final AndroidPackage p2 = mPackages.get(pkg2);
final PackageStateInternal ps1 =
@@ -4196,10 +4266,8 @@ public class ComputerEngine implements Computer {
if (p1 == null || ps1 == null || p2 == null || ps2 == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- if (shouldFilterApplication(ps1, callingUid, callingUserId)
- || shouldFilterApplication(ps2, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps1, callingUid, userId)
+ || shouldFilterApplicationIncludingUninstalled(ps2, callingUid, userId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
return checkSignaturesInternal(p1.getSigningDetails(), p2.getSigningDetails());
@@ -4209,54 +4277,58 @@ public class ComputerEngine implements Computer {
public int checkUidSignatures(int uid1, int uid2) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- // Map to base uids.
- final int appId1 = UserHandle.getAppId(uid1);
- final int appId2 = UserHandle.getAppId(uid2);
- SigningDetails p1SigningDetails;
- SigningDetails p2SigningDetails;
- Object obj = mSettings.getSettingBase(appId1);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p1SigningDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p1SigningDetails = ps.getSigningDetails();
- } else {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- } else {
+ final SigningDetails p1SigningDetails =
+ getSigningDetailsAndFilterAccess(uid1, callingUid, callingUserId);
+ final SigningDetails p2SigningDetails =
+ getSigningDetailsAndFilterAccess(uid2, callingUid, callingUserId);
+ if (p1SigningDetails == null || p2SigningDetails == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- obj = mSettings.getSettingBase(appId2);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p2SigningDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- p2SigningDetails = ps.getSigningDetails();
- } else {
- return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
- }
- } else {
+ return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
+ }
+
+ @Override
+ public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId1 = UserHandle.getUserId(uid1);
+ final int userId2 = UserHandle.getUserId(uid2);
+ enforceCrossUserPermission(callingUid, userId1, false /* requireFullPermission */,
+ false /* checkShell */, "checkUidSignaturesForAllUsers");
+ enforceCrossUserPermission(callingUid, userId2, false /* requireFullPermission */,
+ false /* checkShell */, "checkUidSignaturesForAllUsers");
+ final SigningDetails p1SigningDetails =
+ getSigningDetailsAndFilterAccess(uid1, callingUid, userId1);
+ final SigningDetails p2SigningDetails =
+ getSigningDetailsAndFilterAccess(uid2, callingUid, userId2);
+ if (p1SigningDetails == null || p2SigningDetails == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
}
+ private SigningDetails getSigningDetailsAndFilterAccess(int uid, int callingUid, int userId) {
+ // Map to base uids.
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingBase(appId);
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, userId)) {
+ return null;
+ }
+ return sus.signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
+ return null;
+ }
+ return ps.getSigningDetails();
+ }
+ return null;
+ }
+
private int checkSignaturesInternal(SigningDetails p1SigningDetails,
SigningDetails p2SigningDetails) {
if (p1SigningDetails == null) {
@@ -4319,27 +4391,9 @@ public class ComputerEngine implements Computer {
@PackageManager.CertificateInputType int type) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- // Map to base uids.
- final int appId = UserHandle.getAppId(uid);
- final SigningDetails signingDetails;
- final Object obj = mSettings.getSettingBase(appId);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
- return false;
- }
- signingDetails = sus.signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return false;
- }
- signingDetails = ps.getSigningDetails();
- } else {
- return false;
- }
- } else {
+ final SigningDetails signingDetails =
+ getSigningDetailsAndFilterAccess(uid, callingUid, callingUserId);
+ if (signingDetails == null) {
return false;
}
switch (type) {
@@ -4354,11 +4408,8 @@ public class ComputerEngine implements Computer {
@Override
public List<String> getAllPackages() {
- // Allow iorapd to call this method.
- if (Binder.getCallingUid() != Process.IORAPD_UID) {
- PackageManagerServiceUtils.enforceSystemOrRootOrShell(
- "getAllPackages is limited to privileged callers");
- }
+ PackageManagerServiceUtils.enforceSystemOrRootOrShell(
+ "getAllPackages is limited to privileged callers");
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
if (canViewInstantApps(callingUid, callingUserId)) {
@@ -4405,13 +4456,13 @@ public class ComputerEngine implements Computer {
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return null;
}
return sus.name + ":" + sus.mAppId;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return null;
}
return ps.getPackageName();
@@ -4440,14 +4491,14 @@ public class ComputerEngine implements Computer {
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
names[i] = null;
} else {
names[i] = "shared:" + sus.name;
}
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
names[i] = null;
} else {
names[i] = ps.getPackageName();
@@ -4469,7 +4520,7 @@ public class ComputerEngine implements Computer {
return Process.INVALID_UID;
}
final SharedUserSetting suid = mSettings.getSharedUserFromId(sharedUserName);
- if (suid != null && !shouldFilterApplication(suid, callingUid,
+ if (suid != null && !shouldFilterApplicationIncludingUninstalled(suid, callingUid,
UserHandle.getUserId(callingUid))) {
return suid.mAppId;
}
@@ -4490,13 +4541,13 @@ public class ComputerEngine implements Computer {
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return 0;
}
return sus.getFlags();
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return 0;
}
return ps.getFlags();
@@ -4518,13 +4569,13 @@ public class ComputerEngine implements Computer {
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
- if (shouldFilterApplication(sus, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
return 0;
}
return sus.getPrivateFlags();
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return 0;
}
return ps.getPrivateFlags();
@@ -4563,22 +4614,21 @@ public class ComputerEngine implements Computer {
// NOTE: Can't remove due to unsupported app usage
@NonNull
@Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- if (permissionName == null) {
- return EmptyArray.STRING;
- }
+ public String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId) {
final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
+ enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "getAppOpPermissionPackages");
+ if (permissionName == null || getInstantAppPackageName(callingUid) != null
+ || !mUserManager.exists(userId)) {
return EmptyArray.STRING;
}
- final int callingUserId = UserHandle.getUserId(callingUid);
final ArraySet<String> packageNames = new ArraySet(
mPermissionManager.getAppOpPermissionPackages(permissionName));
for (int i = packageNames.size() - 1; i >= 0; i--) {
final String packageName = packageNames.valueAt(i);
- if (!shouldFilterApplication(mSettings.getPackage(packageName), callingUid,
- callingUserId)) {
+ if (!shouldFilterApplicationIncludingUninstalled(
+ mSettings.getPackage(packageName), callingUid, userId)) {
continue;
}
packageNames.removeAt(i);
@@ -4877,32 +4927,33 @@ public class ComputerEngine implements Computer {
@Nullable
@Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
+ public InstrumentationInfo getInstrumentationInfoAsUser(@NonNull ComponentName component,
+ int flags, int userId) {
final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
+ enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "getInstrumentationInfoAsUser");
+ if (!mUserManager.exists(userId)) return null;
String packageName = component.getPackageName();
final PackageStateInternal ps = mSettings.getPackage(packageName);
AndroidPackage pkg = mPackages.get(packageName);
if (ps == null || pkg == null) return null;
if (shouldFilterApplication(
- ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
+ ps, callingUid, component, TYPE_UNKNOWN, userId)) {
return null;
}
final ParsedInstrumentation i = mInstrumentation.get(component);
- return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId, ps);
+ final PackageUserStateInternal state = ps.getUserStateOrDefault(userId);
+ return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, state, userId, ps);
}
@NonNull
@Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
+ public ParceledListSlice<InstrumentationInfo> queryInstrumentationAsUser(
+ @NonNull String targetPackage, int flags, int userId) {
final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageStateInternal ps = mSettings.getPackage(targetPackage);
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
- return ParceledListSlice.emptyList();
- }
-
+ enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "queryInstrumentationAsUser");
+ if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
final int numInstrumentations = mInstrumentation.size();
@@ -4913,12 +4964,15 @@ public class ComputerEngine implements Computer {
String packageName = p.getPackageName();
AndroidPackage pkg = mPackages.get(packageName);
PackageStateInternal pkgSetting = getPackageStateInternal(packageName);
- if (pkg != null) {
- InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
- pkg, flags, callingUserId, pkgSetting);
- if (ii != null) {
- finalList.add(ii);
- }
+ if (pkg == null || pkgSetting == null
+ || shouldFilterApplication(pkgSetting, callingUid, userId)) {
+ continue;
+ }
+ final PackageUserStateInternal state = pkgSetting.getUserStateOrDefault(userId);
+ InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
+ pkg, flags, state, userId, pkgSetting);
+ if (ii != null) {
+ finalList.add(ii);
}
}
}
@@ -4963,7 +5017,7 @@ public class ComputerEngine implements Computer {
if (ps == null) {
return true;
}
- if (shouldFilterApplication(ps, callingUid, userId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
return true;
}
return ps.getUserStateOrDefault(userId).isHidden();
@@ -4978,7 +5032,7 @@ public class ComputerEngine implements Computer {
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "isPackageSuspendedForUser for user " + userId);
final PackageStateInternal ps = mSettings.getPackage(packageName);
- if (ps == null || shouldFilterApplication(ps, callingUid, userId)) {
+ if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
return ps.getUserStateOrDefault(userId).isSuspended();
@@ -5010,7 +5064,7 @@ public class ComputerEngine implements Computer {
if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) {
return ParceledListSlice.emptyList();
}
- if (shouldFilterApplication(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
final int count = ArrayUtils.size(pkg.getActivities());
@@ -5027,25 +5081,12 @@ public class ComputerEngine implements Computer {
@Override
public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- final PackageStateInternal ps = mSettings.getPackage(packageName);
- if (ps == null || shouldFilterApplication(ps, Binder.getCallingUid(), userId)) {
- return false;
- }
- return mSettings.getBlockUninstall(userId, packageName);
- }
-
- @Nullable
- @Override
- public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- if (isInstantApp) {
- return null;
- }
- PackageStateInternal setting = getPackageStateInternal(packageName, Process.SYSTEM_UID);
- if (setting == null) {
- return null;
+ final PackageStateInternal ps = mSettings.getPackage(packageName);
+ final int callingUid = Binder.getCallingUid();
+ if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
+ return false;
}
- return mAppsFilter.getVisibilityAllowList(this, setting, userIds, getPackageStates());
+ return mSettings.getBlockUninstall(userId, packageName);
}
@Nullable
@@ -5059,7 +5100,7 @@ public class ComputerEngine implements Computer {
String installerPackageName = installSource.installerPackageName;
if (installerPackageName != null) {
final PackageStateInternal ps = mSettings.getPackage(installerPackageName);
- if (ps == null || shouldFilterApplication(ps, callingUid,
+ if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid,
UserHandle.getUserId(callingUid))) {
installerPackageName = null;
}
@@ -5072,12 +5113,12 @@ public class ComputerEngine implements Computer {
final PackageStateInternal ps = mSettings.getPackage(packageName);
// Installer info for Apex is not stored in PackageManager
- if (ps == null && mApexManager.isApexPackage(packageName)) {
+ if (ps == null && mApexPackageInfo.isApexPackage(packageName)) {
return InstallSource.EMPTY;
}
- if (ps == null
- || shouldFilterApplication(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (ps == null || shouldFilterApplicationIncludingUninstalled(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return null;
}
@@ -5102,7 +5143,8 @@ public class ComputerEngine implements Computer {
installerPackageName = installSource.installerPackageName;
if (installerPackageName != null) {
final PackageStateInternal ps = mSettings.getPackage(installerPackageName);
- if (ps == null || shouldFilterApplication(ps, callingUid, userId)) {
+ if (ps == null
+ || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
installerPackageName = null;
}
}
@@ -5127,7 +5169,8 @@ public class ComputerEngine implements Computer {
} else {
initiatingPackageName = installSource.initiatingPackageName;
final PackageStateInternal ps = mSettings.getPackage(initiatingPackageName);
- if (ps == null || shouldFilterApplication(ps, callingUid, userId)) {
+ if (ps == null
+ || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
initiatingPackageName = null;
}
}
@@ -5136,7 +5179,8 @@ public class ComputerEngine implements Computer {
originatingPackageName = installSource.originatingPackageName;
if (originatingPackageName != null) {
final PackageStateInternal ps = mSettings.getPackage(originatingPackageName);
- if (ps == null || shouldFilterApplication(ps, callingUid, userId)) {
+ if (ps == null
+ || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
originatingPackageName = null;
}
}
@@ -5172,7 +5216,7 @@ public class ComputerEngine implements Computer {
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "get enabled");
try {
- if (shouldFilterApplication(
+ if (shouldFilterApplicationIncludingUninstalled(
mSettings.getPackage(packageName), callingUid, userId)) {
throw new PackageManager.NameNotFoundException(packageName);
}
@@ -5201,7 +5245,7 @@ public class ComputerEngine implements Computer {
try {
if (shouldFilterApplication(
mSettings.getPackage(component.getPackageName()), callingUid,
- component, TYPE_UNKNOWN, userId)) {
+ component, TYPE_UNKNOWN, userId, true /* filterUninstall */)) {
throw new PackageManager.NameNotFoundException(component.getPackageName());
}
return mSettings.getComponentEnabledSetting(component, userId);
@@ -5241,10 +5285,11 @@ public class ComputerEngine implements Computer {
if (packageName == null || alias == null) {
return null;
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
final AndroidPackage pkg = mPackages.get(packageName);
- if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ if (pkg == null || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -5261,9 +5306,8 @@ public class ComputerEngine implements Computer {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final AndroidPackage pkg = mPackages.get(packageName);
- if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- callingUid, callingUserId)) {
+ if (pkg == null || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName
+ ", uid:" + callingUid);
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -5286,9 +5330,10 @@ public class ComputerEngine implements Computer {
return false;
}
final AndroidPackage pkg = mPackages.get(packageName);
+ final int callingUserId = UserHandle.getUserId(callingUid);
if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- callingUid, UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -5310,9 +5355,10 @@ public class ComputerEngine implements Computer {
return false;
}
final AndroidPackage pkg = mPackages.get(packageName);
+ final int callingUserId = UserHandle.getUserId(callingUid);
if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- callingUid, UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -5326,14 +5372,21 @@ public class ComputerEngine implements Computer {
@Nullable
@Override
- public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
+ public SparseArray<int[]> getVisibilityAllowLists(@NonNull String packageName,
+ @UserIdInt int[] userIds) {
final PackageStateInternal ps =
getPackageStateInternal(packageName, Process.SYSTEM_UID);
if (ps == null) {
return null;
}
- final SparseArray<int[]> visibilityAllowList = mAppsFilter.getVisibilityAllowList(this, ps,
- new int[]{userId}, getPackageStates());
+ return mAppsFilter.getVisibilityAllowList(this, ps, userIds, getPackageStates());
+ }
+
+ @Nullable
+ @Override
+ public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
+ final SparseArray<int[]> visibilityAllowList = getVisibilityAllowLists(packageName,
+ new int[]{userId});
return visibilityAllowList != null ? visibilityAllowList.get(userId) : null;
}
@@ -5425,13 +5478,10 @@ public class ComputerEngine implements Computer {
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "get install reason");
final PackageStateInternal ps = mSettings.getPackage(packageName);
- if (shouldFilterApplication(ps, callingUid, userId)) {
+ if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
return PackageManager.INSTALL_REASON_UNKNOWN;
}
- if (ps != null) {
- return ps.getUserStateOrDefault(userId).getInstallReason();
- }
- return PackageManager.INSTALL_REASON_UNKNOWN;
+ return ps.getUserStateOrDefault(userId).getInstallReason();
}
@Override
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index daac7c04098a..ff6420c45c39 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -265,8 +265,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
}
private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) {
+ final int callingUserId = mInjector.getCallingUserId();
final int[] enabledProfileIds =
- mInjector.getUserManager().getEnabledProfileIds(mInjector.getCallingUserId());
+ mInjector.getUserManager().getEnabledProfileIds(callingUserId);
if (enabledProfileIds.length < 2) {
return false;
}
@@ -274,13 +275,14 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
return hasRequestedAppOpPermission(
- AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName);
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName,
+ callingUserId);
}
- private boolean hasRequestedAppOpPermission(String permission, String packageName) {
+ private boolean hasRequestedAppOpPermission(String permission, String packageName, int userId) {
try {
String[] packages =
- mInjector.getIPackageManager().getAppOpPermissionPackages(permission);
+ mInjector.getIPackageManager().getAppOpPermissionPackages(permission, userId);
return ArrayUtils.contains(packages, packageName);
} catch (RemoteException exc) {
Slog.e(TAG, "PackageManager dead. Cannot get permission info");
@@ -604,7 +606,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
if (!hasRequestedAppOpPermission(
- AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) {
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName, userId)) {
return false;
}
return isCrossProfilePackageAllowlisted(packageName);
@@ -627,7 +629,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
if (!hasRequestedAppOpPermission(
- AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) {
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName, userId)) {
return false;
}
return !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds);
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 0cdf7bf62f55..b0b9e61ca21c 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -39,7 +39,6 @@ import android.app.ApplicationPackageManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDeleteObserver2;
-import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
@@ -774,7 +773,6 @@ final class DeletePackageHelper {
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
} //end catch
- notifyPackageChangeObserversOnDelete(packageName, versionCode);
// Prune unused static shared libraries which have been cached a period of time
mPm.schedulePruneUnusedStaticSharedLibraries(true /* delay */);
@@ -834,18 +832,6 @@ final class DeletePackageHelper {
return result;
}
- private void notifyPackageChangeObserversOnDelete(String packageName, long version) {
- PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
- pkgChangeEvent.packageName = packageName;
- pkgChangeEvent.version = version;
- pkgChangeEvent.lastUpdateTimeMillis = 0L;
- pkgChangeEvent.newInstalled = false;
- pkgChangeEvent.dataRemoved = false;
- pkgChangeEvent.isDeleted = true;
-
- mPm.notifyPackageChangeObservers(pkgChangeEvent);
- }
-
private static class TempUserState {
public final int enabledState;
@Nullable
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index aabe8a163df7..c1d546ed2751 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -29,6 +29,7 @@ import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_APEX_PKG;
import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_NULL_PKG;
import android.Manifest;
@@ -469,15 +470,13 @@ final class DexOptHelper {
options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (SharedLibraryInfo info : deps) {
- AndroidPackage depPackage = null;
- PackageSetting depPackageSetting = null;
- synchronized (mPm.mLock) {
- depPackage = mPm.mPackages.get(info.getPackageName());
- depPackageSetting = mPm.mSettings.getPackageLPr(info.getPackageName());
- }
- if (depPackage != null && depPackageSetting != null) {
+ Computer snapshot = mPm.snapshotComputer();
+ AndroidPackage depPackage = snapshot.getPackage(info.getPackageName());
+ PackageStateInternal depPackageStateInternal =
+ snapshot.getPackageStateInternal(info.getPackageName());
+ if (depPackage != null && depPackageStateInternal != null) {
// TODO: Analyze and investigate if we (should) profile libraries.
- pdo.performDexOpt(depPackage, depPackageSetting, instructionSets,
+ pdo.performDexOpt(depPackage, depPackageStateInternal, instructionSets,
mPm.getOrCreateCompilerPackageStats(depPackage),
mPm.getDexManager().getPackageUseInfoOrDefault(
depPackage.getPackageName()), libraryOptions);
@@ -574,6 +573,7 @@ final class DexOptHelper {
// First, remove all settings without available packages
remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG);
+ remainingPkgSettings.removeIf(REMOVE_IF_APEX_PKG);
ArrayList<PackageStateInternal> sortTemp = new ArrayList<>(remainingPkgSettings.size());
diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
index 7dc45b58a773..53e97540de23 100644
--- a/services/core/java/com/android/server/pm/DistractingPackageHelper.java
+++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
@@ -27,6 +27,7 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -92,9 +93,9 @@ public final class DistractingPackageHelper {
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
final PackageStateInternal packageState =
- snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
+ if (packageState == null) {
Slog.w(PackageManagerService.TAG,
"Could not find package setting for package: " + packageName
+ ". Skipping...");
@@ -126,7 +127,7 @@ public final class DistractingPackageHelper {
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(
new String[changedPackagesList.size()]);
- sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+ sendDistractingPackagesChanged(snapshot, changedPackages, changedUids.toArray(), userId,
restrictionFlags);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -168,7 +169,7 @@ public final class DistractingPackageHelper {
if (!changedPackages.isEmpty()) {
final String[] packageArray = changedPackages.toArray(
new String[changedPackages.size()]);
- sendDistractingPackagesChanged(packageArray, changedUids.toArray(), userId,
+ sendDistractingPackagesChanged(snapshot, packageArray, changedUids.toArray(), userId,
RESTRICTION_NONE);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -181,18 +182,24 @@ public final class DistractingPackageHelper {
* @param uidList The uids of packages which have suspension changes.
* @param userId The user where packages reside.
*/
- void sendDistractingPackagesChanged(@NonNull String[] pkgList,
+ void sendDistractingPackagesChanged(@NonNull Computer snapshot, @NonNull String[] pkgList,
int[] uidList, int userId, int distractionFlags) {
- final Bundle extras = new Bundle(3);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
- extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
-
+ final List<BroadcastParams> lists = mBroadcastHelper.getBroadcastParams(
+ snapshot, pkgList, uidList, userId);
final Handler handler = mInjector.getHandler();
- handler.post(() -> mBroadcastHelper.sendPackageBroadcast(
- Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null /* pkg */, extras,
- Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
- null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
- null /* allowList */, null /* bOptions */));
+ for (int i = 0; i < lists.size(); i++) {
+ final Bundle extras = new Bundle(3);
+ final BroadcastParams list = lists.get(i);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+ final SparseArray<int[]> allowList = list.getAllowList().size() == 0
+ ? null : list.getAllowList();
+ handler.post(() -> mBroadcastHelper.sendPackageBroadcast(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null /* pkg */,
+ extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
+ null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
+ allowList, null /* bOptions */));
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 276644036def..7352018cb4d0 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -51,7 +51,6 @@ import java.io.PrintWriter;
*/
final class DumpHelper {
private final PermissionManagerServiceInternal mPermissionManager;
- private final ApexManager mApexManager;
private final StorageEventHelper mStorageEventHelper;
private final DomainVerificationManagerInternal mDomainVerificationManager;
private final PackageInstallerService mInstallerService;
@@ -63,7 +62,7 @@ final class DumpHelper {
private final PerUidReadTimeouts[] mPerUidReadTimeouts;
DumpHelper(
- PermissionManagerServiceInternal permissionManager, ApexManager apexManager,
+ PermissionManagerServiceInternal permissionManager,
StorageEventHelper storageEventHelper,
DomainVerificationManagerInternal domainVerificationManager,
PackageInstallerService installerService, String requiredVerifierPackage,
@@ -73,7 +72,6 @@ final class DumpHelper {
ArraySet<String> protectedBroadcasts,
PerUidReadTimeouts[] perUidReadTimeouts) {
mPermissionManager = permissionManager;
- mApexManager = apexManager;
mStorageEventHelper = storageEventHelper;
mDomainVerificationManager = domainVerificationManager;
mInstallerService = installerService;
@@ -271,7 +269,7 @@ final class DumpHelper {
// Return if the package doesn't exist.
if (packageName != null
&& snapshot.getPackageStateInternal(packageName) == null
- && !mApexManager.isApexPackage(packageName)) {
+ && !snapshot.isApexPackage(packageName)) {
pw.println("Unable to find package: " + packageName);
return;
}
@@ -553,10 +551,8 @@ final class DumpHelper {
mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_APEX)
- && (packageName == null || mApexManager.isApexPackage(packageName))) {
- mApexManager.dump(pw, packageName);
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
+ snapshot.dump(DumpState.DUMP_APEX, fd, pw, dumpState);
}
if (!checkin
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 043661302f8f..f4285eb0d9d9 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -148,10 +148,10 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Override
@Deprecated
- public final boolean activitySupportsIntent(ComponentName component, Intent intent,
- String resolvedType) {
- return snapshot().activitySupportsIntent(mResolveComponentName, component, intent,
- resolvedType);
+ public final boolean activitySupportsIntentAsUser(ComponentName component, Intent intent,
+ String resolvedType, int userId) {
+ return snapshot().activitySupportsIntentAsUser(mResolveComponentName, component, intent,
+ resolvedType, userId);
}
@Override
@@ -230,8 +230,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Override
@Deprecated
- public final int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
- return snapshot().checkSignatures(pkg1, pkg2);
+ public final int checkSignatures(@NonNull String pkg1, @NonNull String pkg2, int userId) {
+ return snapshot().checkSignatures(pkg1, pkg2, userId);
}
@Override
@@ -324,8 +324,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@NonNull
@Override
@Deprecated
- public final String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- return snapshot().getAppOpPermissionPackages(permissionName);
+ public final String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId) {
+ return snapshot().getAppOpPermissionPackages(permissionName, userId);
}
@Override
@@ -533,9 +533,9 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Nullable
@Override
@Deprecated
- public final InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component,
- int flags) {
- return snapshot().getInstrumentationInfo(component, flags);
+ public final InstrumentationInfo getInstrumentationInfoAsUser(@NonNull ComponentName component,
+ int flags, int userId) {
+ return snapshot().getInstrumentationInfoAsUser(component, flags, userId);
}
@Override
@@ -711,12 +711,17 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Override
@Deprecated
- public final PackageManager.Property getProperty(String propertyName, String packageName,
- String className) {
+ public final PackageManager.Property getPropertyAsUser(String propertyName, String packageName,
+ String className, int userId) {
Objects.requireNonNull(propertyName);
Objects.requireNonNull(packageName);
- PackageStateInternal packageState = snapshot().getPackageStateFiltered(packageName,
- Binder.getCallingUid(), UserHandle.getCallingUserId());
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshot();
+ snapshot.enforceCrossUserOrProfilePermission(callingUid, userId,
+ /* requireFullPermission */ false,
+ /* checkShell */ false, "getPropertyAsUser");
+ PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
if (packageState == null) {
return null;
}
@@ -905,12 +910,6 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Override
@Deprecated
- public final boolean isOnlyCoreApps() {
- return mService.isOnlyCoreApps();
- }
-
- @Override
- @Deprecated
public final boolean isPackageAvailable(String packageName, int userId) {
return snapshot().isPackageAvailable(packageName, userId);
}
@@ -1018,9 +1017,9 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@NonNull
@Override
@Deprecated
- public final ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- return snapshot().queryInstrumentation(targetPackage, flags);
+ public final ParceledListSlice<InstrumentationInfo> queryInstrumentationAsUser(
+ @NonNull String targetPackage, int flags, int userId) {
+ return snapshot().queryInstrumentationAsUser(targetPackage, flags, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index beaa620ab829..4019c15ee550 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -21,6 +21,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FACTORY;
import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
@@ -72,6 +73,7 @@ final class InitAppsHelper {
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
private final ApexManager mApexManager;
+ private final ApexPackageInfo mApexPackageInfo;
private final ExecutorService mExecutorService;
/* Tracks how long system scan took */
private long mSystemScanTime;
@@ -80,7 +82,6 @@ final class InitAppsHelper {
/* Track of the number of system apps */
private int mSystemPackagesCount;
private final boolean mIsDeviceUpgrading;
- private final boolean mIsOnlyCoreApps;
private final List<ScanPartition> mSystemPartitions;
/**
@@ -96,16 +97,17 @@ final class InitAppsHelper {
private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+ InitAppsHelper(PackageManagerService pm,
+ ApexManager apexManager, ApexPackageInfo apexPackageInfo,
InstallPackageHelper installPackageHelper,
List<ScanPartition> systemPartitions) {
mPm = pm;
mApexManager = apexManager;
+ mApexPackageInfo = apexPackageInfo;
mInstallPackageHelper = installPackageHelper;
mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
mIsDeviceUpgrading = mPm.isDeviceUpgrading();
- mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
@@ -169,16 +171,40 @@ final class InitAppsHelper {
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
sp.getFolder().getAbsolutePath() + File.separator)) {
- int flags = SCAN_AS_APK_IN_APEX;
+ int additionalScanFlag = SCAN_AS_APK_IN_APEX;
+ if (apexInfo.isFactory) {
+ additionalScanFlag |= SCAN_AS_FACTORY;
+ }
if (apexInfo.activeApexChanged) {
- flags |= SCAN_DROP_CACHE;
+ additionalScanFlag |= SCAN_DROP_CACHE;
}
- return new ScanPartition(apexInfo.apexDirectory, sp, flags);
+ return new ScanPartition(apexInfo.apexDirectory, sp, additionalScanFlag);
}
}
return null;
}
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private List<ApexManager.ScanResult> scanApexPackagesTraced(PackageParser2 packageParser) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackages");
+
+ try {
+ final List<ApexManager.ScanResult> apexScanResults;
+ if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
+ apexScanResults = mInstallPackageHelper.scanApexPackages(
+ mApexManager.getAllApexInfos(), mSystemParseFlags, mSystemScanFlags,
+ packageParser, mExecutorService);
+ mApexPackageInfo.notifyScanResult(apexScanResults);
+ } else {
+ apexScanResults = mApexPackageInfo.scanApexPackages(
+ mApexManager.getAllApexInfos(), packageParser, mExecutorService);
+ }
+ return apexScanResults;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
/**
* Install apps from system dirs.
*/
@@ -188,7 +214,8 @@ final class InitAppsHelper {
int[] userIds, long startTime) {
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
+ final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser);
+ mApexManager.notifyScanResult(apexScanResults);
scanSystemDirs(packageParser, mExecutorService);
// Parse overlay configuration files to set default enable state, mutability, and
@@ -204,12 +231,10 @@ final class InitAppsHelper {
pkg -> consumer.accept(pkg, pkg.isSystem(),
apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- if (!mIsOnlyCoreApps) {
- // do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(mStubSystemApps);
- mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
- }
+ // do this first before mucking with mPackages for the "expecting better" case
+ updateStubSystemAppsList(mStubSystemApps);
+ mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
+ mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
logSystemAppsScanningTime(startTime);
return overlayConfig;
@@ -243,23 +268,18 @@ final class InitAppsHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
long startTime) {
- if (!mIsOnlyCoreApps) {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
- SystemClock.uptimeMillis());
- scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
- mScanFlags | SCAN_REQUIRE_KNOWN,
- packageParser, mExecutorService);
- }
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+ SystemClock.uptimeMillis());
+ scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
+ mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService);
List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
- if (!mIsOnlyCoreApps) {
- fixSystemPackages(userIds);
- logNonSystemAppScanningTime(startTime);
- }
+ fixSystemPackages(userIds);
+ logNonSystemAppScanningTime(startTime);
mExpectingBetter.clear();
mPm.mSettings.pruneRenamedPackagesLPw();
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c710120ca437..4218a3715214 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -59,7 +59,9 @@ import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.PackageManagerService.POST_INSTALL;
import static com.android.server.pm.PackageManagerService.PRECOMPILE_LAYOUTS;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FACTORY;
import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
@@ -92,6 +94,7 @@ import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.apex.ApexInfo;
import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.backup.IBackupManager;
@@ -102,7 +105,6 @@ import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.IPackageInstallObserver2;
-import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -320,6 +322,12 @@ final class InstallPackageHelper {
pkgSetting.setInstallSource(installSource);
}
+ if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+ boolean isFactory = (scanFlags & SCAN_AS_FACTORY) != 0;
+ pkgSetting.getPkgState().setApkInApex(true);
+ pkgSetting.getPkgState().setApkInUpdatedApex(!isFactory);
+ }
+
// TODO(toddke): Consider a method specifically for modifying the Package object
// post scan; or, moving this stuff out of the Package object since it has nothing
// to do with the package on disk.
@@ -873,7 +881,16 @@ final class InstallPackageHelper {
+ " got: " + apexes.length);
}
try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
- mApexManager.installPackage(apexes[0], packageParser);
+ ApexInfo apexInfo = mApexManager.installPackage(apexes[0]);
+ if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
+ ParsedPackage parsedPackage = packageParser.parsePackage(
+ new File(apexInfo.modulePath), 0, /* useCaches= */ false);
+ scanSystemPackageLI(parsedPackage, 0, SCAN_AS_APEX, null);
+ mPm.mApexPackageInfo.notifyPackageInstalled(
+ apexInfo, parsedPackage.hideAsFinal());
+ } else {
+ mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser);
+ }
}
} catch (PackageManagerException e) {
request.mInstallResult.setError("APEX installation failed", e);
@@ -2353,29 +2370,11 @@ final class InstallPackageHelper {
// BackgroundDexOptService will remove it from its denylist.
// TODO: Layering violation
BackgroundDexOptService.getService().notifyPackageChanged(packageName);
-
- notifyPackageChangeObserversOnUpdate(reconciledPkg);
}
PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental(
incrementalStorages);
}
- private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
- final PackageSetting pkgSetting = reconciledPkg.mPkgSetting;
- final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.mInstallResult;
- final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.mRemovedInfo;
-
- PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
- pkgChangeEvent.packageName = pkgSetting.getPkg().getPackageName();
- pkgChangeEvent.version = pkgSetting.getVersionCode();
- pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.getLastUpdateTime();
- pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.mIsUpdate);
- pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.mDataRemoved);
- pkgChangeEvent.isDeleted = false;
-
- mPm.notifyPackageChangeObservers(pkgChangeEvent);
- }
-
public int installLocationPolicy(PackageInfoLite pkgLite, int installFlags) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
@@ -2478,8 +2477,8 @@ final class InstallPackageHelper {
long requiredInstalledVersionCode, int installFlags) {
String packageName = pkgLite.packageName;
- final PackageInfo activePackage = mApexManager.getPackageInfo(packageName,
- ApexManager.MATCH_ACTIVE_PACKAGE);
+ final PackageInfo activePackage = mPm.snapshotComputer().getPackageInfo(
+ packageName, PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM);
if (activePackage == null) {
String errorMsg = "Attempting to install new APEX package " + packageName;
Slog.w(TAG, errorMsg);
@@ -2639,11 +2638,10 @@ final class InstallPackageHelper {
Slog.i(TAG, "upgrading pkg " + res.mRemovedInfo.mRemovedPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
- final int[] uidArray = new int[]{res.mRemovedInfo.mUid};
- final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(res.mRemovedInfo.mRemovedPackage);
- mBroadcastHelper.sendResourcesChangedBroadcast(
- false, true, pkgList, uidArray, null);
+ final String[] pkgNames = new String[]{res.mRemovedInfo.mRemovedPackage};
+ final int[] uids = new int[]{res.mRemovedInfo.mUid};
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(),
+ false /* mediaStatus */, true /* replacing */, pkgNames, uids);
}
res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
@@ -2815,11 +2813,10 @@ final class InstallPackageHelper {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
}
- final int[] uidArray = new int[]{res.mPkg.getUid()};
- ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(packageName);
- mBroadcastHelper.sendResourcesChangedBroadcast(
- true, true, pkgList, uidArray, null);
+ final String[] pkgNames = new String[]{packageName};
+ final int[] uids = new int[]{res.mPkg.getUid()};
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(),
+ true /* mediaStatus */, true /* replacing */, pkgNames, uids);
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
// No need to kill consumers if it's installation of new version static shared lib.
@@ -3397,6 +3394,50 @@ final class InstallPackageHelper {
}
}
+ public List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages, int parseFlags,
+ int scanFlags, PackageParser2 packageParser, ExecutorService executorService) {
+ if (allPackages == null) {
+ return Collections.EMPTY_LIST;
+ }
+
+ ParallelPackageParser parallelPackageParser =
+ new ParallelPackageParser(packageParser, executorService);
+
+ // Submit files for parsing in parallel
+ ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
+ for (ApexInfo ai : allPackages) {
+ File apexFile = new File(ai.modulePath);
+ parallelPackageParser.submit(apexFile, parseFlags);
+ parsingApexInfo.put(apexFile, ai);
+ }
+
+ // Process results one by one
+ List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
+ for (int i = 0; i < parsingApexInfo.size(); i++) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
+ int newScanFlags = scanFlags | SCAN_AS_APEX;
+
+ if (throwable == null) {
+ try {
+ scanSystemPackageLI(parseResult.parsedPackage, parseFlags, newScanFlags, null);
+ AndroidPackage pkg = parseResult.parsedPackage.hideAsFinal();
+ results.add(new ApexManager.ScanResult(ai, pkg, pkg.getPackageName()));
+ } catch (PackageManagerException e) {
+ throw new IllegalStateException("Failed to scan: " + ai.modulePath, e);
+ }
+ } else if (throwable instanceof PackageManagerException) {
+ throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + ai.modulePath, throwable);
+ }
+ }
+
+ return results;
+ }
+
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
int scanFlags, PackageParser2 packageParser,
@@ -4104,8 +4145,12 @@ final class InstallPackageHelper {
// after OTA.
final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
+ // It is allowed to install a new APEX with the same name. But there shouldn't be
+ // conflicting names between APK and APEX.
+ final boolean installApex = (scanFlags & SCAN_AS_APEX) != 0;
if ((isUserInstall || isFirstBootOrUpgrade)
- && mApexManager.isApexPackage(pkg.getPackageName())) {
+ && mPm.snapshotComputer().isApexPackage(pkg.getPackageName())
+ && !installApex) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
pkg.getPackageName()
+ " is an APEX package and can't be installed as an APK.");
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index 18d2b0c23320..fb189fb6d02c 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -158,15 +158,13 @@ final class InstallParams extends HandlerParams {
return InstallLocationUtils.getInstallationErrorCode(recommendedInstallLocation);
}
// Override with defaults if needed.
- synchronized (mPm.mLock) {
- // reader
- AndroidPackage installedPkg = mPm.mPackages.get(packageName);
- if (installedPkg != null) {
- // Currently installed package which the new package is attempting to replace
- recommendedInstallLocation = InstallLocationUtils.installLocationPolicy(
- installLocation, recommendedInstallLocation, mInstallFlags,
- installedPkg.isSystem(), installedPkg.isExternalStorage());
- }
+ Computer snapshot = mPm.snapshotComputer();
+ AndroidPackage installedPkg = snapshot.getPackage(packageName);
+ if (installedPkg != null) {
+ // Currently installed package which the new package is attempting to replace
+ recommendedInstallLocation = InstallLocationUtils.installLocationPolicy(
+ installLocation, recommendedInstallLocation, mInstallFlags,
+ installedPkg.isSystem(), installedPkg.isExternalStorage());
}
final boolean onInt = (mInstallFlags & PackageManager.INSTALL_INTERNAL) != 0;
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index c5ca06cc7b84..05f84e37499d 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -80,10 +80,9 @@ public final class MovePackageHelper {
final PackageManager pm = mPm.mContext.getPackageManager();
Computer snapshot = mPm.snapshotComputer();
- final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || packageState.getPkg() == null
- || snapshot.shouldFilterApplication(packageState, callingUid, user.getIdentifier())) {
+ final PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, user.getIdentifier());
+ if (packageState == null || packageState.getPkg() == null) {
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
final AndroidPackage pkg = packageState.getPkg();
@@ -303,10 +302,8 @@ public final class MovePackageHelper {
* @param packageName The package that was moved.
*/
private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
- final AndroidPackage pkg;
- synchronized (mPm.mLock) {
- pkg = mPm.mPackages.get(packageName);
- }
+ final Computer snapshot = mPm.snapshotComputer();
+ final AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
return;
}
@@ -334,26 +331,26 @@ public final class MovePackageHelper {
@GuardedBy("mPm.mInstallLock")
private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
- final PackageSetting ps;
- synchronized (mPm.mLock) {
- ps = mPm.mSettings.getPackageLPr(packageName);
- if (ps == null) {
- Slog.w(TAG, "Failed to find settings for " + packageName);
- return false;
- }
+ final Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageStateInternal =
+ snapshot.getPackageStateInternal(packageName);
+ if (packageStateInternal == null) {
+ Slog.w(TAG, "Failed to find settings for " + packageName);
+ return false;
}
final String[] packageNames = { packageName };
- final long[] ceDataInodes = { ps.getCeDataInode(userId) };
- final String[] codePaths = { ps.getPathString() };
+ final long[] ceDataInodes = {
+ packageStateInternal.getUserStateOrDefault(userId).getCeDataInode() };
+ final String[] codePaths = { packageStateInternal.getPathString() };
try {
- mPm.mInstaller.getAppSize(ps.getVolumeUuid(), packageNames, userId, 0,
- ps.getAppId(), ceDataInodes, codePaths, stats);
+ mPm.mInstaller.getAppSize(packageStateInternal.getVolumeUuid(), packageNames, userId,
+ 0, packageStateInternal.getAppId(), ceDataInodes, codePaths, stats);
// For now, ignore code size of packages on system partition
- if (PackageManagerServiceUtils.isSystemApp(ps)
- && !PackageManagerServiceUtils.isUpdatedSystemApp(ps)) {
+ if (PackageManagerServiceUtils.isSystemApp(packageStateInternal)
+ && !PackageManagerServiceUtils.isUpdatedSystemApp(packageStateInternal)) {
stats.codeSize = 0;
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index cc4a76034b2b..e4dcf1aca623 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -142,6 +142,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
others = new ArrayList<>(allPackageStates);
others.removeAll(important);
others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG);
+ others.removeIf(PackageManagerServiceUtils.REMOVE_IF_APEX_PKG);
others.removeIf(isPlatformPackage);
// Pre-size the array list by over-allocating by a factor of 1.5.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 37bfbb11948a..47eff4975a1d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -299,6 +299,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final SessionParams params;
final long createdMillis;
+ /** Used for tracking whether user action was required for an install. */
+ @Nullable
+ private Boolean mUserActionRequired;
+
/** Staging location where client data is written. */
final File stageDir;
final String stageCid;
@@ -2131,9 +2135,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* in its belong session set. When the user answers the yes,
* {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is
* handled to come back here to check again.
+ *
+ * {@code mUserActionRequired} is used to track when user action is required for an
+ * install. Since control may come back here more than 1 time, we must ensure that it's
+ * value is not overwritten.
*/
- if (sendPendingUserActionIntentIfNeeded()) {
+ boolean wasUserActionIntentSent = sendPendingUserActionIntentIfNeeded();
+ if (mUserActionRequired == null) {
+ mUserActionRequired = wasUserActionIntentSent;
+ }
+ if (wasUserActionIntentSent) {
+ // Commit was keeping session marked as active until now; release
+ // that extra refcount so session appears idle.
+ deactivate();
return;
+ } else if (mUserActionRequired) {
+ // If user action is required, control comes back here when the user allows
+ // the installation. At this point, the session is marked active once again,
+ // since installation is in progress.
+ activate();
}
if (params.isStaged) {
@@ -2403,10 +2423,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
sendOnUserActionRequired(mContext, target, sessionId, intent);
-
- // Commit was keeping session marked as active until now; release
- // that extra refcount so session appears idle.
- closeInternal(false);
}
@WorkerThread
@@ -3328,6 +3344,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ /**
+ * @return a boolean value indicating whether user action was requested for the install.
+ * Returns {@code false} if {@code mUserActionRequired} is {@code null}
+ */
+ public boolean getUserActionRequired() {
+ if (mUserActionRequired != null) {
+ return mUserActionRequired.booleanValue();
+ }
+ Slog.wtf(TAG, "mUserActionRequired should not be null.");
+ return false;
+ }
+
private static String getRelativePath(File file, File base) throws IOException {
final String pathStr = file.getAbsolutePath();
final String baseStr = base.getAbsolutePath();
@@ -3460,10 +3488,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
public void open() throws IOException {
- if (mActiveCount.getAndIncrement() == 0) {
- mCallback.onSessionActiveChanged(this, true);
- }
-
+ activate();
boolean wasPrepared;
synchronized (mLock) {
wasPrepared = mPrepared;
@@ -3485,21 +3510,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private void activate() {
+ if (mActiveCount.getAndIncrement() == 0) {
+ mCallback.onSessionActiveChanged(this, true);
+ }
+ }
+
@Override
public void close() {
closeInternal(true);
}
private void closeInternal(boolean checkCaller) {
- int activeCount;
synchronized (mLock) {
if (checkCaller) {
assertCallerIsOwnerOrRoot();
}
+ }
+ deactivate();
+ }
+ private void deactivate() {
+ int activeCount;
+ synchronized (mLock) {
activeCount = mActiveCount.decrementAndGet();
}
-
if (activeCount == 0) {
mCallback.onSessionActiveChanged(this, false);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 652847ad1647..b594866fdf44 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -541,12 +541,6 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final boolean isOnlyCoreApps() {
- return mService.isOnlyCoreApps();
- }
-
- @Override
- @Deprecated
public final void freeStorage(String volumeUuid, long bytes,
@StorageManager.AllocateFlags int flags) throws IOException {
mService.freeStorage(volumeUuid, bytes, flags);
@@ -637,7 +631,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
public final boolean isApexPackage(String packageName) {
- return getApexManager().isApexPackage(packageName);
+ return snapshot().isApexPackage(packageName);
}
@Override
@@ -726,6 +720,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
return snapshot().isUidPrivileged(uid);
}
+ @Override
+ public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
+ return snapshot().checkUidSignaturesForAllUsers(uid1, uid2);
+ }
+
@NonNull
@Override
@Deprecated
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
index 9a43008acfdf..77d2ec970567 100644
--- a/services/core/java/com/android/server/pm/PackageManagerNative.java
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -20,20 +20,16 @@ import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static com.android.server.pm.PackageManagerService.TAG;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInfo;
import android.content.pm.StagedApexInfo;
import android.os.Binder;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Slog;
import java.util.Arrays;
@@ -46,35 +42,6 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
}
@Override
- public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
- synchronized (mPm.mPackageChangeObservers) {
- try {
- observer.asBinder().linkToDeath(
- new PackageChangeObserverDeathRecipient(observer), 0);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage());
- }
- mPm.mPackageChangeObservers.add(observer);
- Log.d(TAG, "Size of mPackageChangeObservers after registry is "
- + mPm.mPackageChangeObservers.size());
- }
- }
-
- @Override
- public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
- synchronized (mPm.mPackageChangeObservers) {
- mPm.mPackageChangeObservers.remove(observer);
- Log.d(TAG, "Size of mPackageChangeObservers after unregistry is "
- + mPm.mPackageChangeObservers.size());
- }
- }
-
- @Override
- public String[] getAllPackages() {
- return mPm.snapshotComputer().getAllPackages().toArray(new String[0]);
- }
-
- @Override
public String[] getNamesForUids(int[] uids) throws RemoteException {
String[] names = null;
String[] results = null;
@@ -222,21 +189,4 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
public StagedApexInfo getStagedApexInfo(String moduleName) {
return mPm.mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
}
-
- private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
- private final IPackageChangeObserver mObserver;
-
- PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) {
- mObserver = observer;
- }
-
- @Override
- public void binderDied() {
- synchronized (mPm.mPackageChangeObservers) {
- mPm.mPackageChangeObservers.remove(mObserver);
- Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is "
- + mPm.mPackageChangeObservers.size());
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 621ad5223de2..ebce22716644 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -80,7 +80,6 @@ import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IOnChecksumsReadyListener;
-import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
@@ -92,7 +91,6 @@ import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
import android.content.pm.ModuleInfo;
-import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -377,6 +375,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
static final int SCAN_DROP_CACHE = 1 << 24;
+ static final int SCAN_AS_FACTORY = 1 << 25;
+ static final int SCAN_AS_APEX = 1 << 26;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -552,7 +552,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private final int mSdkVersion;
final Context mContext;
final boolean mFactoryTest;
- private final boolean mOnlyCore;
final DisplayMetrics mMetrics;
private final int mDefParseFlags;
private final String[] mSeparateProcesses;
@@ -678,6 +677,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private final ModuleInfoProvider mModuleInfoProvider;
final ApexManager mApexManager;
+ final ApexPackageInfo mApexPackageInfo;
final PackageManagerServiceInjector mInjector;
@@ -691,10 +691,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private @NonNull final OverlayConfig mOverlayConfig;
- @GuardedBy("itself")
- final ArrayList<IPackageChangeObserver> mPackageChangeObservers =
- new ArrayList<>();
-
// Cached parsed flag value. Invalidated on each flag change.
PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
@@ -803,6 +799,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
+ // Recorded overlay paths configuration for the Android app info.
+ private String[] mPlatformPackageOverlayPaths = null;
+ private String[] mPlatformPackageOverlayResourceDirs = null;
+ // And the same paths for the replaced resolver activity package
+ private String[] mReplacedResolverPackageOverlayPaths = null;
+ private String[] mReplacedResolverPackageOverlayResourceDirs = null;
+
private boolean mResolverReplaced = false;
@NonNull
@@ -1403,7 +1406,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public static Pair<PackageManagerService, IPackageManager> main(Context context,
Installer installer, @NonNull DomainVerificationService domainVerificationService,
- boolean factoryTest, boolean onlyCore) {
+ boolean factoryTest) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -1425,8 +1428,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> PermissionManagerService.create(context,
i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
- new UserDataPreparer(installer, installLock, context, onlyCore),
- lock),
+ new UserDataPreparer(installer, installLock, context), lock),
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
@@ -1448,14 +1450,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
() -> LocalServices.getService(UserManagerInternal.class)),
(i, pm) -> new DisplayMetrics(),
- (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
- i.getDisplayMetrics(), pm.mCacheDir,
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(),
+ pm.mCacheDir,
pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
- (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
- i.getDisplayMetrics(), null,
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* scanningPackageParserProducer */,
- (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
- null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
+ pm.mPackageParserCallback) /* preparingPackageParserProducer */,
// Prepare a supplier of package parser for the staging manager to parse apex file
// during the staging installation.
(i, pm) -> new PackageInstallerService(
@@ -1483,7 +1484,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
- PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
+ PackageManagerService m = new PackageManagerService(injector, factoryTest,
PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);
t.traceEnd(); // "create package manager"
@@ -1611,6 +1612,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mSharedLibraries = injector.getSharedLibrariesImpl();
mApexManager = testParams.apexManager;
+ mApexPackageInfo = new ApexPackageInfo();
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mBackgroundDexOptService = testParams.backgroundDexOptService;
@@ -1632,7 +1634,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mMetrics = testParams.Metrics;
mModuleInfoProvider = testParams.moduleInfoProvider;
mMoveCallbacks = testParams.moveCallbacks;
- mOnlyCore = testParams.onlyCore;
mOverlayConfig = testParams.overlayConfig;
mPackageDexOptimizer = testParams.packageDexOptimizer;
mPackageParserCallback = testParams.packageParserCallback;
@@ -1694,9 +1695,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
invalidatePackageInfoCache();
}
- public PackageManagerService(PackageManagerServiceInjector injector, boolean onlyCore,
- boolean factoryTest, final String buildFingerprint, final boolean isEngBuild,
- final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
+ public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest,
+ final String buildFingerprint, final boolean isEngBuild, final boolean isUserDebugBuild,
+ final int sdkVersion, final String incrementalVersion) {
mIsEngBuild = isEngBuild;
mIsUserDebugBuild = isUserDebugBuild;
mSdkVersion = sdkVersion;
@@ -1718,7 +1719,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mContext = injector.getContext();
mFactoryTest = factoryTest;
- mOnlyCore = onlyCore;
mMetrics = injector.getDisplayMetrics();
mInstaller = injector.getInstaller();
mEnableFreeCacheV2 = SystemProperties.getBoolean("fw.free_cache_v2", true);
@@ -1812,6 +1812,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = injector.getApexManager();
+ mApexPackageInfo = new ApexPackageInfo();
mAppsFilter = mInjector.getAppsFilter();
mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
@@ -1829,8 +1830,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
- mInjector.getSystemPartitions());
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mApexPackageInfo,
+ mInstallPackageHelper, mInjector.getSystemPartitions());
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1841,10 +1842,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mDexOptHelper = new DexOptHelper(this);
mSuspendPackageHelper = new SuspendPackageHelper(this, mInjector, mBroadcastHelper,
mProtectedPackages);
- mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper,
- mRemovePackageHelper);
mDistractingPackageHelper = new DistractingPackageHelper(this, mInjector, mBroadcastHelper,
mSuspendPackageHelper);
+ mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper,
+ mRemovePackageHelper);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
@@ -1916,7 +1917,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
mPermissionManager.readLegacyPermissionStateTEMP();
- if (!mOnlyCore && mFirstBoot) {
+ if (mFirstBoot) {
DexOptHelper.requestCopyPreoptedFiles();
}
@@ -2067,21 +2068,19 @@ public class PackageManagerService implements PackageSender, TestUtilityService
StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
ver.sdkVersion = mSdkVersion;
- // If this is the first boot or an update from pre-M, and it is a normal
- // boot, then we need to initialize the default preferred apps across
- // all defined users.
- if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
+ // If this is the first boot or an update from pre-M, then we need to initialize the
+ // default preferred apps across all defined users.
+ if (mPromoteSystemApps || mFirstBoot) {
for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(user.id);
}
}
- // If this is first boot after an OTA, and a normal boot, then
- // we need to clear code cache directories.
+ // If this is first boot after an OTA, then we need to clear code cache directories.
// Note that we do *not* clear the application profiles. These remain valid
// across OTAs and are used to drive profile verification (post OTA) and
// profile compilation (without waiting to collect a fresh set of profiles).
- if (mIsUpgrade && !mOnlyCore) {
+ if (mIsUpgrade) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < packageSettings.size(); i++) {
final PackageSetting ps = packageSettings.valueAt(i);
@@ -2101,7 +2100,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
// Legacy existing (installed before Q) non-system apps to hide
// their icons in launcher.
- if (!mOnlyCore && mIsPreQUpgrade) {
+ if (mIsPreQUpgrade) {
Slog.i(TAG, "Allowlisting all existing apps to hide their icons");
int size = packageSettings.size();
for (int i = 0; i < size; i++) {
@@ -2127,33 +2126,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
- if (!mOnlyCore) {
- mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(computer);
- mRequiredInstallerPackage = getRequiredInstallerLPr(computer);
- mRequiredUninstallerPackage = getRequiredUninstallerLPr(computer);
- ComponentName intentFilterVerifierComponent =
- getIntentFilterVerifierComponentNameLPr(computer);
- ComponentName domainVerificationAgent =
- getDomainVerificationAgentComponentNameLPr(computer);
-
- DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy(
- intentFilterVerifierComponent, domainVerificationAgent, mContext,
- mDomainVerificationManager, mDomainVerificationManager.getCollector(),
- mDomainVerificationConnection);
-
- mDomainVerificationManager.setProxy(domainVerificationProxy);
-
- mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer);
- mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer,
- PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
- SharedLibraryInfo.VERSION_UNDEFINED);
- } else {
- mRequiredVerifierPackage = null;
- mRequiredInstallerPackage = null;
- mRequiredUninstallerPackage = null;
- mServicesExtensionPackageName = null;
- mSharedSystemSharedLibraryPackageName = null;
- }
+ mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(computer);
+ mRequiredInstallerPackage = getRequiredInstallerLPr(computer);
+ mRequiredUninstallerPackage = getRequiredUninstallerLPr(computer);
+ ComponentName intentFilterVerifierComponent =
+ getIntentFilterVerifierComponentNameLPr(computer);
+ ComponentName domainVerificationAgent =
+ getDomainVerificationAgentComponentNameLPr(computer);
+
+ DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy(
+ intentFilterVerifierComponent, domainVerificationAgent, mContext,
+ mDomainVerificationManager, mDomainVerificationManager.getCollector(),
+ mDomainVerificationConnection);
+
+ mDomainVerificationManager.setProxy(domainVerificationProxy);
+
+ mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer);
+ mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer,
+ PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
+ SharedLibraryInfo.VERSION_UNDEFINED);
// PermissionController hosts default permission granting and role management, so it's a
// critical part of the core system.
@@ -2267,11 +2258,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return mFirstBoot;
}
- public boolean isOnlyCoreApps() {
- // allow instant applications
- return mOnlyCore;
- }
-
public boolean isDeviceUpgrading() {
// allow instant applications
// The system property allows testing ota flow when upgraded to the same image.
@@ -3137,23 +3123,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
});
}
- void notifyPackageChangeObservers(PackageChangeEvent event) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
- synchronized (mPackageChangeObservers) {
- for (IPackageChangeObserver observer : mPackageChangeObservers) {
- try {
- observer.onPackageChanged(event);
- } catch (RemoteException e) {
- Log.wtf(TAG, e);
- }
- }
- }
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
@SuppressWarnings("GuardedBy")
VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
if (pkg.isExternalStorage()) {
@@ -3686,27 +3655,26 @@ public class PackageManagerService implements PackageSender, TestUtilityService
snapshot.getPackagesForUid(callingUid), packageName);
final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
// Limit who can change which apps
- if (!isCallerTargetApp) {
+ if (!isCallerTargetApp && !allowedByPermission) {
// Don't allow apps that don't have permission to modify other apps
- if (!allowedByPermission
- || snapshot.shouldFilterApplication(pkgSetting, callingUid, userId)) {
- throw new SecurityException("Attempt to change component state; "
- + "pid=" + Binder.getCallingPid()
- + ", uid=" + callingUid
- + (!setting.isComponent() ? ", package=" + packageName
- : ", component=" + setting.getComponentName()));
- }
- // Don't allow changing protected packages.
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
- throw new SecurityException(
- "Cannot disable a protected package: " + packageName);
- }
+ throw new SecurityException("Attempt to change component state; "
+ + "pid=" + Binder.getCallingPid()
+ + ", uid=" + callingUid
+ + (!setting.isComponent() ? ", package=" + packageName
+ : ", component=" + setting.getComponentName()));
}
- if (pkgSetting == null) {
+ if (pkgSetting == null || snapshot.shouldFilterApplicationIncludingUninstalled(
+ pkgSetting, callingUid, userId)) {
throw new IllegalArgumentException(setting.isComponent()
? "Unknown component: " + setting.getComponentName()
: "Unknown package: " + packageName);
}
+ // Don't allow changing protected packages.
+ if (!isCallerTargetApp
+ && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ throw new SecurityException(
+ "Cannot disable a protected package: " + packageName);
+ }
if (callingUid == Process.SHELL_UID
&& (pkgSetting.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Shell can only change whole packages between ENABLED and DISABLED_USER states
@@ -3962,8 +3930,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
snapshot.isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- final SparseArray<int[]> broadcastAllowList = snapshot.getBroadcastAllowList(
- packageName, userIds, isInstantApp);
+ final SparseArray<int[]> broadcastAllowList =
+ isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
mHandler.post(() -> mBroadcastHelper.sendPackageChangedBroadcast(
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
instantUserIds, broadcastAllowList));
@@ -4422,12 +4390,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService
true /* requireFullPermission */, true /* checkShell */, "stop package");
final PackageStateInternal packageState =
- snapshot.getPackageStateInternal(packageName);
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
final PackageUserState packageUserState = packageState == null
? null : packageState.getUserStateOrDefault(userId);
- if (packageState != null
- && !snapshot.shouldFilterApplication(packageState, callingUid, userId)
- && packageUserState.isStopped() != stopped) {
+ if (packageState != null && packageUserState.isStopped() != stopped) {
boolean wasNotLaunched = packageUserState.isNotLaunched();
commitPackageStateMutation(null, packageName, state -> {
PackageUserStateWrite userState = state.userState(userId);
@@ -4482,8 +4449,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public void clearApplicationProfileData(String packageName) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system can clear all profile data");
+ PackageManagerServiceUtils.enforceSystemOrRootOrShell(
+ "Only the system or shell can clear all profile data");
final Computer snapshot = snapshotComputer();
final AndroidPackage pkg = snapshot.getPackage(packageName);
@@ -4505,7 +4472,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "clear application data");
- if (snapshot.getPackageStateFiltered(packageName, callingUid, userId) == null) {
+ if (snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId) == null) {
if (observer != null) {
mHandler.post(() -> {
try {
@@ -4962,9 +4930,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String getPermissionControllerPackageName() {
final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
final Computer snapshot = snapshotComputer();
- if (snapshot.getPackageStateFiltered(mRequiredPermissionControllerPackage,
- callingUid, UserHandle.getUserId(callingUid)) != null) {
+ if (snapshot.getPackageStateForInstalledAndFiltered(
+ mRequiredPermissionControllerPackage, callingUid, callingUserId) != null) {
return mRequiredPermissionControllerPackage;
}
@@ -4983,8 +4952,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String getSplashScreenTheme(@NonNull String packageName, int userId) {
final Computer snapshot = snapshotComputer();
- PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
- packageName, Binder.getCallingUid(), userId);
+ final int callingUid = Binder.getCallingUid();
+ snapshot.enforceCrossUserPermission(
+ callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "getSplashScreenTheme");
+ PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
return packageState == null ? null
: packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
}
@@ -5275,11 +5248,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final int callingUserId = UserHandle.getCallingUserId();
final Computer snapshot = snapshotComputer();
final List<PackageManager.Property> result =
- mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
- final PackageStateInternal ps =
- snapshot.getPackageStateInternal(packageName);
- return snapshot.shouldFilterApplication(ps, callingUid, callingUserId);
- });
+ mPackageProperty.queryProperty(propertyName, componentType,
+ packageName -> snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, callingUserId) == null
+ );
if (result == null) {
return ParceledListSlice.emptyList();
}
@@ -5390,8 +5362,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mInjector.getSystemService(AppOpsManager.class)
.checkPackage(Binder.getCallingUid(), callerPackageName);
- PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
- Binder.getCallingUid(), UserHandle.getCallingUserId());
+ PackageStateInternal packageState = computer.getPackageStateForInstalledAndFiltered(
+ packageName, Binder.getCallingUid(), UserHandle.getCallingUserId());
if (packageState == null) {
throw new IllegalArgumentException("Unknown target package " + packageName);
}
@@ -5460,7 +5432,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final long callingId = Binder.clearCallingIdentity();
try {
final PackageStateInternal packageState =
- snapshot.getPackageStateFiltered(packageName, callingUid, userId);
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
if (packageState == null) {
return false;
}
@@ -5637,19 +5610,17 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
PackageStateInternal targetPackageState =
- snapshot.getPackageStateInternal(targetPackage);
- if (targetPackageState == null
- || snapshot.shouldFilterApplication(targetPackageState, callingUid,
- callingUserId)) {
+ snapshot.getPackageStateForInstalledAndFiltered(
+ targetPackage, callingUid, callingUserId);
+ if (targetPackageState == null) {
throw new IllegalArgumentException("Unknown target package: " + targetPackage);
}
PackageStateInternal installerPackageState = null;
if (installerPackageName != null) {
- installerPackageState = snapshot.getPackageStateInternal(installerPackageName);
- if (installerPackageState == null
- || snapshot.shouldFilterApplication(
- installerPackageState, callingUid, callingUserId)) {
+ installerPackageState = snapshot.getPackageStateForInstalledAndFiltered(
+ installerPackageName, callingUid, callingUserId);
+ if (installerPackageState == null) {
throw new IllegalArgumentException("Unknown installer package: "
+ installerPackageName);
}
@@ -5863,7 +5834,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
false /* checkShell */, "setSplashScreenTheme");
enforceOwnerRights(snapshot, packageName, callingUid);
- PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+ PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
packageName, callingUid, userId);
if (packageState == null) {
return;
@@ -5974,7 +5945,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
synchronized (mProtectedBroadcasts) {
protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts);
}
- new DumpHelper(mPermissionManager, mApexManager, mStorageEventHelper,
+ new DumpHelper(mPermissionManager, mStorageEventHelper,
mDomainVerificationManager, mInstallerService, mRequiredVerifierPackage,
knownPackages, mChangedPackagesTracker, availableFeatures, protectedBroadcasts,
getPerUidReadTimeouts(snapshot)
@@ -6201,7 +6172,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Override
- public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
+ public void pruneCachedApksInApex(@NonNull List<String> apexPackageNames) {
if (mCacheDir == null) {
return;
}
@@ -6209,9 +6180,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final PackageCacher cacher = new PackageCacher(mCacheDir);
synchronized (mLock) {
final Computer snapshot = snapshot();
- for (int i = 0, size = apexPackages.size(); i < size; i++) {
+ for (int i = 0, size = apexPackageNames.size(); i < size; i++) {
final List<String> apkNames =
- mApexManager.getApksInApex(apexPackages.get(i).packageName);
+ mApexManager.getApksInApex(apexPackageNames.get(i));
for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
final AndroidPackage pkg = snapshot.getPackage(apkNames.get(j));
cacher.cleanCachedResult(new File(pkg.getPath()));
@@ -6272,11 +6243,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Override
- public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
- @Nullable OverlayPaths overlayPaths,
- @NonNull Set<String> outUpdatedPackageNames) {
- return PackageManagerService.this.setEnabledOverlayPackages(userId, targetPackageName,
- overlayPaths, outUpdatedPackageNames);
+ public void setEnabledOverlayPackages(int userId,
+ @NonNull ArrayMap<String, OverlayPaths> pendingChanges,
+ @NonNull Set<String> outUpdatedPackageNames,
+ @NonNull Set<String> outInvalidPackageNames) {
+ PackageManagerService.this.setEnabledOverlayPackages(userId,
+ pendingChanges, outUpdatedPackageNames, outInvalidPackageNames);
}
@Override
@@ -6340,8 +6312,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return;
}
final ApexManager am = PackageManagerService.this.mApexManager;
- PackageInfo activePackage = am.getPackageInfo(packageName,
- ApexManager.MATCH_ACTIVE_PACKAGE);
+ PackageInfo activePackage = snapshot().getPackageInfo(
+ packageName, PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM);
if (activePackage == null) {
adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
packageName + " is not an apex package");
@@ -6434,7 +6406,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public boolean registerInstalledLoadingProgressCallback(String packageName,
PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
final Computer snapshot = snapshotComputer();
- final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered(
packageName, Binder.getCallingUid(), userId);
if (ps == null) {
return false;
@@ -6457,7 +6429,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public IncrementalStatesInfo getIncrementalStatesInfo(
@NonNull String packageName, int filterCallingUid, int userId) {
final Computer snapshot = snapshotComputer();
- final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered(
packageName, filterCallingUid, userId);
if (ps == null) {
return null;
@@ -6486,85 +6458,173 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
- private boolean setEnabledOverlayPackages(@UserIdInt int userId,
- @NonNull String targetPackageName, @Nullable OverlayPaths newOverlayPaths,
- @NonNull Set<String> outUpdatedPackageNames) {
+ private void setEnabledOverlayPackages(@UserIdInt int userId,
+ @NonNull ArrayMap<String, OverlayPaths> pendingChanges,
+ @NonNull Set<String> outUpdatedPackageNames,
+ @NonNull Set<String> outInvalidPackageNames) {
+ final ArrayMap<String, ArrayMap<String, ArraySet<String>>>
+ targetPkgToLibNameToModifiedDependents = new ArrayMap<>();
+ final int numberOfPendingChanges = pendingChanges.size();
+
synchronized (mOverlayPathsLock) {
- final ArrayMap<String, ArraySet<String>> libNameToModifiedDependents = new ArrayMap<>();
Computer computer = snapshotComputer();
- final PackageStateInternal packageState = computer.getPackageStateInternal(
- targetPackageName);
- final AndroidPackage targetPkg = packageState == null ? null : packageState.getPkg();
- if (targetPackageName == null || targetPkg == null) {
- Slog.e(TAG, "failed to find package " + targetPackageName);
- return false;
- }
+ for (int i = 0; i < numberOfPendingChanges; i++) {
+ final String targetPackageName = pendingChanges.keyAt(i);
+ final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i);
+ final PackageStateInternal packageState = computer.getPackageStateInternal(
+ targetPackageName);
+ final AndroidPackage targetPkg =
+ packageState == null ? null : packageState.getPkg();
+ if (targetPackageName == null || targetPkg == null) {
+ Slog.e(TAG, "failed to find package " + targetPackageName);
+ outInvalidPackageNames.add(targetPackageName);
+ continue;
+ }
- if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(),
- newOverlayPaths)) {
- return true;
- }
+ if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(),
+ newOverlayPaths)) {
+ continue;
+ }
- if (targetPkg.getLibraryNames() != null) {
- // Set the overlay paths for dependencies of the shared library.
- for (final String libName : targetPkg.getLibraryNames()) {
- ArraySet<String> modifiedDependents = null;
+ if (targetPkg.getLibraryNames() != null) {
+ // Set the overlay paths for dependencies of the shared library.
+ for (final String libName : targetPkg.getLibraryNames()) {
+ ArraySet<String> modifiedDependents = null;
- final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName,
- SharedLibraryInfo.VERSION_UNDEFINED);
- if (info == null) {
- continue;
- }
- final List<VersionedPackage> dependents = computer
- .getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, userId);
- if (dependents == null) {
- continue;
- }
- for (final VersionedPackage dependent : dependents) {
- final PackageStateInternal dependentState =
- computer.getPackageStateInternal(dependent.getPackageName());
- if (dependentState == null) {
+ final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName,
+ SharedLibraryInfo.VERSION_UNDEFINED);
+ if (info == null) {
continue;
}
- if (!Objects.equals(dependentState.getUserStateOrDefault(userId)
- .getSharedLibraryOverlayPaths()
- .get(libName), newOverlayPaths)) {
- String dependentPackageName = dependent.getPackageName();
- modifiedDependents = ArrayUtils.add(modifiedDependents,
- dependentPackageName);
- outUpdatedPackageNames.add(dependentPackageName);
+ final List<VersionedPackage> dependents =
+ computer.getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID,
+ userId);
+ if (dependents == null) {
+ continue;
+ }
+ for (final VersionedPackage dependent : dependents) {
+ final PackageStateInternal dependentState =
+ computer.getPackageStateInternal(dependent.getPackageName());
+ if (dependentState == null) {
+ continue;
+ }
+ if (!Objects.equals(dependentState.getUserStateOrDefault(userId)
+ .getSharedLibraryOverlayPaths()
+ .get(libName), newOverlayPaths)) {
+ String dependentPackageName = dependent.getPackageName();
+ modifiedDependents = ArrayUtils.add(modifiedDependents,
+ dependentPackageName);
+ outUpdatedPackageNames.add(dependentPackageName);
+ }
}
- }
- if (modifiedDependents != null) {
- libNameToModifiedDependents.put(libName, modifiedDependents);
+ if (modifiedDependents != null) {
+ ArrayMap<String, ArraySet<String>> libNameToModifiedDependents =
+ targetPkgToLibNameToModifiedDependents.get(
+ targetPackageName);
+ if (libNameToModifiedDependents == null) {
+ libNameToModifiedDependents = new ArrayMap<>();
+ targetPkgToLibNameToModifiedDependents.put(targetPackageName,
+ libNameToModifiedDependents);
+ }
+ libNameToModifiedDependents.put(libName, modifiedDependents);
+ }
}
}
- }
- outUpdatedPackageNames.add(targetPackageName);
+ outUpdatedPackageNames.add(targetPackageName);
+ }
commitPackageStateMutation(null, mutator -> {
- mutator.forPackage(targetPackageName)
- .userState(userId)
- .setOverlayPaths(newOverlayPaths);
-
- for (int mapIndex = 0; mapIndex < libNameToModifiedDependents.size(); mapIndex++) {
- String libName = libNameToModifiedDependents.keyAt(mapIndex);
- ArraySet<String> modifiedDependents =
- libNameToModifiedDependents.valueAt(mapIndex);
- for (int setIndex = 0; setIndex < modifiedDependents.size(); setIndex++) {
- mutator.forPackage(modifiedDependents.valueAt(setIndex))
- .userState(userId)
- .setOverlayPathsForLibrary(libName, newOverlayPaths);
+ for (int i = 0; i < numberOfPendingChanges; i++) {
+ final String targetPackageName = pendingChanges.keyAt(i);
+ final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i);
+
+ if (!outUpdatedPackageNames.contains(targetPackageName)) {
+ continue;
+ }
+
+ mutator.forPackage(targetPackageName)
+ .userState(userId)
+ .setOverlayPaths(newOverlayPaths);
+
+ final ArrayMap<String, ArraySet<String>> libNameToModifiedDependents =
+ targetPkgToLibNameToModifiedDependents.get(
+ targetPackageName);
+ if (libNameToModifiedDependents == null) {
+ continue;
+ }
+
+ for (int mapIndex = 0; mapIndex < libNameToModifiedDependents.size();
+ mapIndex++) {
+ String libName = libNameToModifiedDependents.keyAt(mapIndex);
+ ArraySet<String> modifiedDependents =
+ libNameToModifiedDependents.valueAt(mapIndex);
+ for (int setIndex = 0; setIndex < modifiedDependents.size(); setIndex++) {
+ mutator.forPackage(modifiedDependents.valueAt(setIndex))
+ .userState(userId)
+ .setOverlayPathsForLibrary(libName, newOverlayPaths);
+ }
}
}
});
}
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Keep the overlays in the system application info (and anything special cased as well)
+ // up to date to make sure system ui is themed correctly.
+ for (int i = 0; i < numberOfPendingChanges; i++) {
+ final String targetPackageName = pendingChanges.keyAt(i);
+ final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i);
+ maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths);
+ }
+ }
+
invalidatePackageInfoCache();
+ }
- return true;
+ private void maybeUpdateSystemOverlays(String targetPackageName, OverlayPaths newOverlayPaths) {
+ if (!mResolverReplaced) {
+ if (targetPackageName.equals("android")) {
+ if (newOverlayPaths == null) {
+ mPlatformPackageOverlayPaths = null;
+ mPlatformPackageOverlayResourceDirs = null;
+ } else {
+ mPlatformPackageOverlayPaths = newOverlayPaths.getOverlayPaths().toArray(
+ new String[0]);
+ mPlatformPackageOverlayResourceDirs = newOverlayPaths.getResourceDirs().toArray(
+ new String[0]);
+ }
+ applyUpdatedSystemOverlayPaths();
+ }
+ } else {
+ if (targetPackageName.equals(mResolveActivity.applicationInfo.packageName)) {
+ if (newOverlayPaths == null) {
+ mReplacedResolverPackageOverlayPaths = null;
+ mReplacedResolverPackageOverlayResourceDirs = null;
+ } else {
+ mReplacedResolverPackageOverlayPaths =
+ newOverlayPaths.getOverlayPaths().toArray(new String[0]);
+ mReplacedResolverPackageOverlayResourceDirs =
+ newOverlayPaths.getResourceDirs().toArray(new String[0]);
+ }
+ applyUpdatedSystemOverlayPaths();
+ }
+ }
+ }
+
+ private void applyUpdatedSystemOverlayPaths() {
+ if (mAndroidApplication == null) {
+ Slog.i(TAG, "Skipped the AndroidApplication overlay paths update - no app yet");
+ } else {
+ mAndroidApplication.overlayPaths = mPlatformPackageOverlayPaths;
+ mAndroidApplication.resourceDirs = mPlatformPackageOverlayResourceDirs;
+ }
+ if (mResolverReplaced) {
+ mResolveActivity.applicationInfo.overlayPaths = mReplacedResolverPackageOverlayPaths;
+ mResolveActivity.applicationInfo.resourceDirs =
+ mReplacedResolverPackageOverlayResourceDirs;
+ }
}
private void enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
@@ -6597,21 +6657,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return mSettings.getDisabledSystemPkgLPr(packageName);
}
- @Nullable
- private PackageStateInternal filterPackageStateForInstalledAndFiltered(
- @NonNull Computer computer, @NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- PackageStateInternal packageState =
- computer.getPackageStateInternal(packageName, callingUid);
- if (packageState == null
- || computer.shouldFilterApplication(packageState, callingUid, userId)
- || !packageState.getUserStateOrDefault(userId).isInstalled()) {
- return null;
- } else {
- return packageState;
- }
- }
-
@Deprecated
void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {
@@ -7043,6 +7088,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
PackageManagerService.onChanged();
}
+ applyUpdatedSystemOverlayPaths();
}
ApplicationInfo getCoreAndroidApplication() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 16829e0e8f6c..f44d922ea716 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -115,6 +115,6 @@ public final class PackageManagerServiceTestParams {
public ResolveIntentHelper resolveIntentHelper;
public DexOptHelper dexOptHelper;
public SuspendPackageHelper suspendPackageHelper;
- public StorageEventHelper storageEventHelper;
public DistractingPackageHelper distractingPackageHelper;
+ public StorageEventHelper storageEventHelper;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 6afc5890a6a7..e3dc271d8991 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -136,7 +136,10 @@ public class PackageManagerServiceUtils {
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
- public final static Predicate<PackageStateInternal> REMOVE_IF_NULL_PKG =
+ // Skip APEX which doesn't have a valid UID
+ public static final Predicate<PackageStateInternal> REMOVE_IF_APEX_PKG =
+ pkgSetting -> pkgSetting.getPkg().isApex();
+ public static final Predicate<PackageStateInternal> REMOVE_IF_NULL_PKG =
pkgSetting -> pkgSetting.getPkg() == null;
/**
@@ -1077,11 +1080,11 @@ public class PackageManagerServiceUtils {
return null;
}
- public static boolean isSystemApp(PackageSetting ps) {
+ public static boolean isSystemApp(PackageStateInternal ps) {
return (ps.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
}
- public static boolean isUpdatedSystemApp(PackageSetting ps) {
+ public static boolean isUpdatedSystemApp(PackageStateInternal ps) {
return (ps.getFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1eb74facb840..5906c3f3f39f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -23,6 +23,8 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQU
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+
import android.accounts.IAccountManager;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -109,8 +111,10 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
+import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
+import com.android.server.art.ArtManagerLocal;
import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationShell;
@@ -347,6 +351,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runBypassAllowedApexUpdateCheck();
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
+ case "art":
+ return runArtSubCommand();
default: {
Boolean domainVerificationResult =
mDomainVerificationShell.runCommand(this, cmd);
@@ -371,6 +377,8 @@ class PackageManagerShellCommand extends ShellCommand {
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
+ } catch (ManagerNotFoundException e) {
+ pw.println(e);
}
return -1;
}
@@ -780,7 +788,9 @@ class PackageManagerShellCommand extends ShellCommand {
}
final List<InstrumentationInfo> list =
- mInterface.queryInstrumentation(targetPackage, 0 /*flags*/).getList();
+ mInterface.queryInstrumentationAsUser(
+ targetPackage, PackageManager.MATCH_KNOWN_PACKAGES, UserHandle.USER_SYSTEM)
+ .getList();
// sort by target package
Collections.sort(list, new Comparator<InstrumentationInfo>() {
@@ -895,6 +905,9 @@ class PackageManagerShellCommand extends ShellCommand {
getFlags |= PackageManager.MATCH_APEX;
listApexOnly = true;
break;
+ case "--factory-only":
+ getFlags |= PackageManager.MATCH_FACTORY_ONLY;
+ break;
case "--user":
defaultUserId = UserHandle.parseUserArg(getNextArgRequired());
break;
@@ -3397,6 +3410,15 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
+ private int runArtSubCommand() throws ManagerNotFoundException {
+ // Remove the first arg "art" and forward to ART module.
+ String[] args = getAllArgs();
+ args = Arrays.copyOfRange(args, 1, args.length);
+ return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
+ .handleShellCommand(getTarget(), getInFileDescriptor(), getOutFileDescriptor(),
+ getErrFileDescriptor(), args);
+ }
+
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
@@ -3905,7 +3927,8 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" Prints all system libraries.");
pw.println("");
pw.println(" list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] ");
- pw.println(" [--show-versioncode] [--apex-only] [--uid UID] [--user USER_ID] [FILTER]");
+ pw.println(" [--show-versioncode] [--apex-only] [--factory-only]");
+ pw.println(" [--uid UID] [--user USER_ID] [FILTER]");
pw.println(" Prints all packages; optionally only those whose name contains");
pw.println(" the text in FILTER. Options are:");
pw.println(" -f: see their associated file");
@@ -3920,6 +3943,7 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" -u: also include uninstalled packages");
pw.println(" --show-versioncode: also show the version code");
pw.println(" --apex-only: only show APEX packages");
+ pw.println(" --factory-only: only show system packages excluding updates");
pw.println(" --uid UID: filter to only show packages with the given UID");
pw.println(" --user USER_ID: only list packages belonging to the given user");
pw.println("");
@@ -4257,6 +4281,9 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" --reset: restore the installer and throttle time to the default, and");
pw.println(" clear tracks of silent updates in the system.");
pw.println("");
+ pw.println(" art [<SUB-COMMANDS>]");
+ pw.println(" Invokes ART services commands. (Run `pm art help` for details.)");
+ pw.println("");
mDomainVerificationShell.printHelp(pw);
pw.println("");
Intent.printIntentArgsHelp(pw , "");
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 2016fc3093b3..975a272416d9 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -46,7 +46,6 @@ import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import com.android.server.rollback.RollbackManagerInternal;
import java.io.File;
@@ -101,10 +100,12 @@ final class PackageSessionVerifier {
for (PackageInstallerSession child : session.getChildSessions()) {
checkApexUpdateAllowed(child);
checkRebootlessApex(child);
+ checkApexSignature(child);
}
} else {
checkApexUpdateAllowed(session);
checkRebootlessApex(session);
+ checkApexSignature(session);
}
verifyAPK(session, callback);
} catch (PackageManagerException e) {
@@ -115,6 +116,47 @@ final class PackageSessionVerifier {
});
}
+ private SigningDetails getSigningDetails(PackageInfo apexPkg) throws PackageManagerException {
+ final String apexPath = apexPkg.applicationInfo.sourceDir;
+ final int minSignatureScheme =
+ ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
+ apexPkg.applicationInfo.targetSdkVersion);
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ApkSignatureVerifier.verify(
+ input, apexPath, minSignatureScheme);
+ if (result.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Failed to verify APEX package " + apexPath + " : "
+ + result.getException(), result.getException());
+ }
+ return result.getResult();
+ }
+
+ private void checkApexSignature(PackageInstallerSession session)
+ throws PackageManagerException {
+ if (!session.isApexSession()) {
+ return;
+ }
+ final String packageName = session.getPackageName();
+ final PackageInfo existingApexPkg = mPm.snapshotComputer().getPackageInfo(
+ session.getPackageName(), PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM);
+ if (existingApexPkg == null) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED,
+ "Attempting to install new APEX package " + packageName);
+ }
+ final SigningDetails existingSigningDetails = getSigningDetails(existingApexPkg);
+ final SigningDetails newSigningDetails = session.getSigningDetails();
+ if (newSigningDetails.checkCapability(existingSigningDetails,
+ SigningDetails.CertCapabilities.INSTALLED_DATA)
+ || existingSigningDetails.checkCapability(newSigningDetails,
+ SigningDetails.CertCapabilities.ROLLBACK)) {
+ return;
+ }
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "APK container signature of APEX package " + packageName
+ + " is not compatible with the one currently installed on device");
+ }
+
/**
* Runs verifications particular to APK. This includes APEX sessions since an APEX can also
* be treated as APK.
@@ -167,7 +209,7 @@ final class PackageSessionVerifier {
}
return new VerificationParams(user, session.stageDir, observer, session.params,
session.getInstallSource(), session.getInstallerUid(), session.getSigningDetails(),
- session.sessionId, session.getPackageLite(), mPm);
+ session.sessionId, session.getPackageLite(), session.getUserActionRequired(), mPm);
}
/**
@@ -283,13 +325,10 @@ final class PackageSessionVerifier {
// APEX checks. For single-package sessions, check if they contain an APEX. For
// multi-package sessions, find all the child sessions that contain an APEX.
if (hasApex) {
- final List<PackageInfo> apexPackages = submitSessionToApexService(session, rollbackId);
- for (int i = 0, size = apexPackages.size(); i < size; i++) {
- validateApexSignature(apexPackages.get(i));
- }
+ final List<String> apexPackageNames = submitSessionToApexService(session, rollbackId);
final PackageManagerInternal packageManagerInternal =
LocalServices.getService(PackageManagerInternal.class);
- packageManagerInternal.pruneCachedApksInApex(apexPackages);
+ packageManagerInternal.pruneCachedApksInApex(apexPackageNames);
}
}
@@ -333,62 +372,7 @@ final class PackageSessionVerifier {
}
}
- /**
- * Validates the signature used to sign the container of the new apex package
- *
- * @param newApexPkg The new apex package that is being installed
- */
- private void validateApexSignature(PackageInfo newApexPkg) throws PackageManagerException {
- // Get signing details of the new package
- final String apexPath = newApexPkg.applicationInfo.sourceDir;
- final String packageName = newApexPkg.packageName;
- int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
- newApexPkg.applicationInfo.targetSdkVersion);
-
- final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
- final ParseResult<SigningDetails> newResult = ApkSignatureVerifier.verify(
- input.reset(), apexPath, minSignatureScheme);
- if (newResult.isError()) {
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Failed to parse APEX package " + apexPath + " : "
- + newResult.getException(), newResult.getException());
- }
- final SigningDetails newSigningDetails = newResult.getResult();
-
- // Get signing details of the existing package
- final PackageInfo existingApexPkg = mApexManager.getPackageInfo(packageName,
- ApexManager.MATCH_ACTIVE_PACKAGE);
- if (existingApexPkg == null) {
- // This should never happen, because submitSessionToApexService ensures that no new
- // apexes were installed.
- throw new IllegalStateException("Unknown apex package " + packageName);
- }
-
- final ParseResult<SigningDetails> existingResult = ApkSignatureVerifier.verify(
- input.reset(), existingApexPkg.applicationInfo.sourceDir,
- SigningDetails.SignatureSchemeVersion.JAR);
- if (existingResult.isError()) {
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
- + " : " + existingResult.getException(), existingResult.getException());
- }
- final SigningDetails existingSigningDetails = existingResult.getResult();
-
- // Verify signing details for upgrade
- if (newSigningDetails.checkCapability(existingSigningDetails,
- SigningDetails.CertCapabilities.INSTALLED_DATA)
- || existingSigningDetails.checkCapability(newSigningDetails,
- SigningDetails.CertCapabilities.ROLLBACK)) {
- return;
- }
-
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "APK-container signature of APEX package " + packageName + " with version "
- + newApexPkg.versionCodeMajor + " and path " + apexPath + " is not"
- + " compatible with the one currently installed on device");
- }
-
- private List<PackageInfo> submitSessionToApexService(StagingManager.StagedSession session,
+ private List<String> submitSessionToApexService(StagingManager.StagedSession session,
int rollbackId) throws PackageManagerException {
final IntArray childSessionIds = new IntArray();
if (session.isMultiPackage()) {
@@ -413,32 +397,22 @@ final class PackageSessionVerifier {
// submitStagedSession will throw a PackageManagerException if apexd verification fails,
// which will be propagated to populate stagedSessionErrorMessage of this session.
final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams);
- final List<PackageInfo> result = new ArrayList<>();
final List<String> apexPackageNames = new ArrayList<>();
for (ApexInfo apexInfo : apexInfoList.apexInfos) {
- final PackageInfo packageInfo;
- final int flags = PackageManager.GET_META_DATA;
+ final ParsedPackage parsedPackage;
try (PackageParser2 packageParser = mPackageParserSupplier.get()) {
File apexFile = new File(apexInfo.modulePath);
- final ParsedPackage parsedPackage = packageParser.parsePackage(
- apexFile, flags, false);
- packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags);
- if (packageInfo == null) {
- throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Unable to generate package info: " + apexInfo.modulePath);
- }
+ parsedPackage = packageParser.parsePackage(apexFile, 0, false);
} catch (PackageManagerException e) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
}
- result.add(packageInfo);
- apexPackageNames.add(packageInfo.packageName);
+ apexPackageNames.add(parsedPackage.getPackageName());
}
Slog.d(TAG, "Session " + session.sessionId() + " has following APEX packages: "
+ apexPackageNames);
- return result;
+ return apexPackageNames;
}
private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2bae00f91b82..f84db1f7abbe 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -1227,6 +1227,11 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return pkgState.isUpdatedSystemApp();
}
+ @Override
+ public boolean isApkInUpdatedApex() {
+ return pkgState.isApkInUpdatedApex();
+ }
+
public PackageSetting setDomainSetId(@NonNull UUID domainSetId) {
mDomainSetId = domainSetId;
onChanged();
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 9befd6e09eb4..0ca5febd0d99 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -48,7 +48,6 @@ import android.util.Xml;
import com.android.internal.util.ArrayUtils;
import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import org.xmlpull.v1.XmlPullParser;
@@ -595,11 +594,7 @@ final class PreferredActivityHelper {
synchronized (mPm.mLock) {
mPm.mSettings.applyDefaultPreferredAppsLPw(userId);
mPm.mDomainVerificationManager.clearUser(userId);
- final int numPackages = mPm.mPackages.size();
- for (int i = 0; i < numPackages; i++) {
- final AndroidPackage pkg = mPm.mPackages.valueAt(i);
- mPm.mPermissionManager.resetRuntimePermissions(pkg, userId);
- }
+ mPm.mPermissionManager.resetRuntimePermissionsForUser(userId);
}
updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
resetNetworkPolicies(userId);
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 0dc188b75d5e..fe160e3fee22 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -24,6 +24,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.PackageManagerService.DEBUG_ABI_SELECTION;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
@@ -853,6 +854,8 @@ final class ScanPackageUtils {
.markNotActivitiesAsNotExportedIfSingleUser();
}
+ parsedPackage.setApex((scanFlags & SCAN_AS_APEX) != 0);
+
parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0)
.setOem((scanFlags & SCAN_AS_OEM) != 0)
.setVendor((scanFlags & SCAN_AS_VENDOR) != 0)
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6400502f1a89..46358606eccb 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -805,7 +805,6 @@ public final class Settings implements Watchable, Snappable {
// always make sure the system package code and resource paths dont change
if (dp == null && p.getPkg() != null && p.getPkg().isSystem()
&& !p.getPkgState().isUpdatedSystemApp()) {
- p.getPkgState().setUpdatedSystemApp(true);
final PackageSetting disabled;
if (replaced) {
// a little trick... when we install the new package, we don't
@@ -816,6 +815,7 @@ public final class Settings implements Watchable, Snappable {
} else {
disabled = p;
}
+ p.getPkgState().setUpdatedSystemApp(true);
mDisabledSysPackages.put(name, disabled);
SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(disabled);
if (sharedUserSetting != null) {
@@ -2691,6 +2691,11 @@ public final class Settings implements Watchable, Snappable {
}
continue;
}
+ if (pkg.getPkg().isApex()) {
+ // Don't persist APEX which doesn't have a valid app id and will cause parsing
+ // error in libpackagelistparser
+ continue;
+ }
final boolean isDebug = pkg.getPkg().isDebuggable();
final IntArray gids = new IntArray();
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 666776b4161e..fe1c83bab30c 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -28,7 +28,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.annotation.NonNull;
import android.app.ResourcesManager;
-import android.content.IIntentReceiver;
import android.content.pm.PackageManager;
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
@@ -223,7 +222,7 @@ public final class StorageEventHelper extends StorageEventListener {
}
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
- sendResourcesChangedBroadcast(true, false, loaded, null);
+ sendResourcesChangedBroadcast(true /* mediaStatus */, false /* replacing */, loaded);
synchronized (mLoadedVolumes) {
mLoadedVolumes.add(vol.getId());
}
@@ -274,7 +273,7 @@ public final class StorageEventHelper extends StorageEventListener {
}
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
- sendResourcesChangedBroadcast(false, false, unloaded, null);
+ sendResourcesChangedBroadcast(false /* mediaStatus */, false /* replacing */, unloaded);
synchronized (mLoadedVolumes) {
mLoadedVolumes.remove(vol.getId());
}
@@ -290,7 +289,7 @@ public final class StorageEventHelper extends StorageEventListener {
}
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
+ ArrayList<AndroidPackage> packages) {
final int size = packages.size();
final String[] packageNames = new String[size];
final int[] packageUids = new int[size];
@@ -299,8 +298,8 @@ public final class StorageEventHelper extends StorageEventListener {
packageNames[i] = pkg.getPackageName();
packageUids[i] = pkg.getUid();
}
- mBroadcastHelper.sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames,
- packageUids, finishedReceiver);
+ mBroadcastHelper.sendResourcesChangedBroadcast(mPm.snapshotComputer(), mediaStatus,
+ replacing, packageNames, packageUids);
}
/**
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 908b12e1752d..f931ba8720db 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -51,7 +51,6 @@ import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
import com.android.server.utils.WatchedArrayMap;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
@@ -128,9 +127,9 @@ public final class SuspendPackageHelper {
continue;
}
final PackageStateInternal packageState =
- snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
+ if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -229,7 +228,8 @@ public final class SuspendPackageHelper {
continue;
}
final PackageStateInternal packageState =
- snapshot.getPackageStateFiltered(packageNames[i], callingUid, userId);
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageNames[i], callingUid, userId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -588,48 +588,19 @@ public final class SuspendPackageHelper {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
void sendPackagesSuspendedForUser(@NonNull Computer snapshot, @NonNull String intent,
@NonNull String[] pkgList, @NonNull int[] uidList, int userId) {
- final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
- final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
- final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
- final int[] userIds = new int[] {userId};
- // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if
- // allow lists are the same.
- for (int i = 0; i < pkgList.length; i++) {
- final String pkgName = pkgList[i];
- final int uid = uidList[i];
- SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
- snapshot, snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
- userIds, snapshot.getPackageStates());
- if (allowList == null) {
- allowList = new SparseArray<>(0);
- }
- boolean merged = false;
- for (int j = 0; j < allowListsToSend.size(); j++) {
- if (Arrays.equals(allowListsToSend.get(j).get(userId), allowList.get(userId))) {
- pkgsToSend.get(j).add(pkgName);
- uidsToSend.get(j).add(uid);
- merged = true;
- break;
- }
- }
- if (!merged) {
- pkgsToSend.add(new ArrayList<>(Arrays.asList(pkgName)));
- uidsToSend.add(IntArray.wrap(new int[] {uid}));
- allowListsToSend.add(allowList);
- }
- }
-
+ final List<BroadcastParams> lists = mBroadcastHelper.getBroadcastParams(
+ snapshot, pkgList, uidList, userId);
final Handler handler = mInjector.getHandler();
- for (int i = 0; i < pkgsToSend.size(); i++) {
+ for (int i = 0; i < lists.size(); i++) {
final Bundle extras = new Bundle(3);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- pkgsToSend.get(i).toArray(new String[pkgsToSend.get(i).size()]));
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
- final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
- ? null : allowListsToSend.get(i);
+ final BroadcastParams list = lists.get(i);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, list.getPackageNames());
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, list.getUids());
+ final SparseArray<int[]> allowList = list.getAllowList().size() == 0
+ ? null : list.getAllowList();
handler.post(() -> mBroadcastHelper.sendPackageBroadcast(intent, null /* pkg */,
extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
- null /* finishedReceiver */, userIds, null /* instantUserIds */,
+ null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
allowList, null /* bOptions */));
}
}
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 974a1e1cd59d..7260f94ede67 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -54,13 +54,11 @@ class UserDataPreparer {
private final Object mInstallLock;
private final Context mContext;
- private final boolean mOnlyCore;
private final Installer mInstaller;
- UserDataPreparer(Installer installer, Object installLock, Context context, boolean onlyCore) {
+ UserDataPreparer(Installer installer, Object installLock, Context context) {
mInstallLock = installLock;
mContext = context;
- mOnlyCore = onlyCore;
mInstaller = installer;
}
@@ -92,13 +90,13 @@ class UserDataPreparer {
try {
storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
- if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
enforceSerialNumber(getDataUserDeDirectory(volumeUuid, userId), userSerial);
if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
enforceSerialNumber(getDataSystemDeDirectory(userId), userSerial);
}
}
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
enforceSerialNumber(getDataUserCeDirectory(volumeUuid, userId), userSerial);
if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
enforceSerialNumber(getDataSystemCeDirectory(userId), userSerial);
@@ -167,14 +165,18 @@ class UserDataPreparer {
if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
- FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
+ // Delete the contents of /data/system_de/$userId, but not the directory itself
+ // since vold is responsible for that and system_server isn't allowed to do it.
+ FileUtils.deleteContents(getDataSystemDeDirectory(userId));
}
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
+ // Likewise, delete the contents of /data/system_ce/$userId but not the
+ // directory itself.
+ FileUtils.deleteContents(getDataSystemCeDirectory(userId));
}
}
- // Data with special labels is now gone, so finish the job
+ // All the user's data directories should be empty now, so finish the job.
storage.destroyUserStorage(volumeUuid, userId, flags);
} catch (Exception e) {
@@ -231,7 +233,7 @@ class UserDataPreparer {
logCriticalInfo(Log.WARN, "Destroying user directory " + file
+ " because no matching user was found");
destroyUser = true;
- } else if (!mOnlyCore) {
+ } else {
try {
enforceSerialNumber(file, info.serialNumber);
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9de485b28479..2d32aa4248bc 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -32,6 +32,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
@@ -111,6 +112,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
@@ -120,9 +122,11 @@ import com.android.server.BundleUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemService;
+import com.android.server.UiThread;
import com.android.server.am.UserState;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
+import com.android.server.power.ShutdownThread;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -194,6 +198,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
private static final String ATTR_SEED_ACCOUNT_NAME = "seedAccountName";
private static final String ATTR_SEED_ACCOUNT_TYPE = "seedAccountType";
+
private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
private static final String TAG_USERS = "users";
private static final String TAG_USER = "user";
@@ -213,6 +218,7 @@ public class UserManagerService extends IUserManager.Stub {
"lastRequestQuietModeEnabledCall";
private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
"ignorePrepareStorageErrors";
+
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -285,6 +291,7 @@ public class UserManagerService extends IUserManager.Stub {
private final Handler mHandler;
private final File mUsersDir;
+ @GuardedBy("mPackagesLock")
private final File mUserListFile;
private static final IBinder mUserRestriconToken = new Binder();
@@ -295,6 +302,9 @@ public class UserManagerService extends IUserManager.Stub {
private PackageManagerInternal mPmInternal;
private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
+ /** Indicates that this is the 1st boot after the system user mode was changed by emulation. */
+ private boolean mUpdatingSystemUserMode;
+
/**
* Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
*/
@@ -481,7 +491,7 @@ public class UserManagerService extends IUserManager.Stub {
private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
new ArrayList<>();
- @GuardedBy("mUserRemovedListeners")
+ @GuardedBy("mUserLifecycleListeners")
private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
private final LockPatternUtils mLockPatternUtils;
@@ -721,6 +731,7 @@ public class UserManagerService extends IUserManager.Stub {
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
+ emulateSystemUserModeIfNeeded();
}
void systemReady() {
@@ -1878,6 +1889,44 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
+ public boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
+ checkCreateUsersPermission("update ephemeral user flag");
+ UserData userToUpdate = null;
+ synchronized (mPackagesLock) {
+ synchronized (mUsersLock) {
+ final UserData userData = mUsers.get(userId);
+ if (userData == null) {
+ Slog.e(LOG_TAG, "User not found for setting ephemeral mode: u" + userId);
+ return false;
+ }
+ boolean isEphemeralUser = (userData.info.flags & UserInfo.FLAG_EPHEMERAL) != 0;
+ boolean isEphemeralOnCreateUser =
+ (userData.info.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) != 0;
+ // when user is created in ephemeral mode via FLAG_EPHEMERAL
+ // its state cannot be changed to non ephemeral.
+ // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
+ if (isEphemeralOnCreateUser && !enableEphemeral) {
+ Slog.e(LOG_TAG, "Failed to change user state to non-ephemeral for user "
+ + userId);
+ return false;
+ }
+ if (isEphemeralUser != enableEphemeral) {
+ if (enableEphemeral) {
+ userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
+ } else {
+ userData.info.flags &= ~UserInfo.FLAG_EPHEMERAL;
+ }
+ userToUpdate = userData;
+ }
+ }
+ if (userToUpdate != null) {
+ writeUserLP(userToUpdate);
+ }
+ }
+ return true;
+ }
+
+ @Override
public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) {
try {
checkManageUsersPermission("update users");
@@ -2091,6 +2140,7 @@ public class UserManagerService extends IUserManager.Stub {
* exist in device policy local restrictions, remove the restrictions bundle for that target
* user originating from the specified originating user.
*/
+ @GuardedBy("mRestrictionsLock")
private boolean updateLocalRestrictionsForTargetUsersLR(int originatingUserId,
RestrictionsSet local, List<Integer> updatedTargetUserIds) {
boolean changed = false;
@@ -2113,6 +2163,7 @@ public class UserManagerService extends IUserManager.Stub {
*
* @return restrictions set for a given target user.
*/
+ @GuardedBy("mRestrictionsLock")
private @NonNull RestrictionsSet getDevicePolicyLocalRestrictionsForTargetUserLR(
int targetUserId) {
RestrictionsSet result = mDevicePolicyLocalUserRestrictions.get(targetUserId);
@@ -2363,6 +2414,7 @@ public class UserManagerService extends IUserManager.Stub {
mAppliedUserRestrictions.updateRestrictions(userId, new Bundle(effective));
}
+ @GuardedBy("mRestrictionsLock")
private void propagateUserRestrictionsLR(final int userId,
Bundle newRestrictions, Bundle prevRestrictions) {
// Note this method doesn't touch any state, meaning it doesn't require mRestrictionsLock
@@ -2836,6 +2888,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @GuardedBy({"mPackagesLock"})
private void writeBitmapLP(UserInfo info, Bitmap bitmap) {
try {
File dir = new File(mUsersDir, Integer.toString(info.id));
@@ -2894,7 +2947,86 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
+ /**
+ * Checks whether the device is really headless system user mode, ignoring system user mode
+ * emulation.
+ */
+ private boolean isReallyHeadlessSystemUserMode() {
+ return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
+ }
+
+ /**
+ * Called on boot to change the system user mode (for example, from headless to full or
+ * vice versa) for development purposes.
+ */
+ private void emulateSystemUserModeIfNeeded() {
+ if (!Build.isDebuggable()) {
+ return;
+ }
+
+ final String emulatedValue = SystemProperties
+ .get(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY);
+ if (TextUtils.isEmpty(emulatedValue)) {
+ return;
+ }
+
+ final boolean newHeadlessSystemUserMode;
+ switch (emulatedValue) {
+ case UserManager.SYSTEM_USER_MODE_EMULATION_FULL:
+ newHeadlessSystemUserMode = false;
+ break;
+ case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS:
+ newHeadlessSystemUserMode = true;
+ break;
+ case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT:
+ newHeadlessSystemUserMode = isReallyHeadlessSystemUserMode();
+ break;
+ default:
+ Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): ignoring invalid valued of "
+ + "property %s: %s", UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY,
+ emulatedValue);
+ return;
+ }
+
+ // Update system user type
+ synchronized (mPackagesLock) {
+ synchronized (mUsersLock) {
+ final UserData systemUserData = mUsers.get(UserHandle.USER_SYSTEM);
+ if (systemUserData == null) {
+ Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): no system user data");
+ return;
+ }
+ final int oldFlags = systemUserData.info.flags;
+ final int newFlags;
+ final String newUserType;
+ if (newHeadlessSystemUserMode) {
+ newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
+ newFlags = oldFlags & ~UserInfo.FLAG_FULL;
+ } else {
+ newUserType = UserManager.USER_TYPE_FULL_SYSTEM;
+ newFlags = oldFlags | UserInfo.FLAG_FULL;
+ }
+
+ if (systemUserData.info.userType.equals(newUserType)) {
+ Slogf.d(LOG_TAG, "emulateSystemUserModeIfNeeded(): system user type is already "
+ + "%s, returning", newUserType);
+ return;
+ }
+ Slogf.i(LOG_TAG, "Persisting emulated system user data: type changed from %s to "
+ + "%s, flags changed from %s to %s",
+ systemUserData.info.userType, newUserType,
+ UserInfo.flagsToString(oldFlags), UserInfo.flagsToString(newFlags));
+ systemUserData.info.userType = newUserType;
+ systemUserData.info.flags = newFlags;
+ writeUserLP(systemUserData);
+ }
+ }
+
+ // Update emulated mode, which will used to triger an update on user packages
+ mUpdatingSystemUserMode = true;
+ }
+
+ @GuardedBy({"mPackagesLock"})
private void readUserListLP() {
if (!mUserListFile.exists()) {
fallbackToSingleUserLP();
@@ -2962,8 +3094,10 @@ public class UserManagerService extends IUserManager.Stub {
} else if (name.equals(TAG_DEVICE_OWNER_USER_ID)
// Legacy name, should only be encountered when upgrading from pre-O.
|| name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
- mDeviceOwnerUserId =
- parser.getAttributeInt(null, ATTR_ID, mDeviceOwnerUserId);
+ synchronized (mRestrictionsLock) {
+ mDeviceOwnerUserId =
+ parser.getAttributeInt(null, ATTR_ID, mDeviceOwnerUserId);
+ }
} else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
// Should only happen when upgrading from pre-O (version < 7).
oldDevicePolicyGlobalUserRestrictions =
@@ -2985,7 +3119,7 @@ public class UserManagerService extends IUserManager.Stub {
* Upgrade steps between versions, either for fixing bugs or changing the data format.
* @param oldGlobalUserRestrictions Pre-O global device policy restrictions.
*/
- @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
+ @GuardedBy({"mPackagesLock"})
private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
upgradeIfNecessaryLP(oldGlobalUserRestrictions, mUserVersion, mUserTypeVersion);
}
@@ -2994,7 +3128,7 @@ public class UserManagerService extends IUserManager.Stub {
* Version of {@link #upgradeIfNecessaryLP(Bundle)} that takes in the userVersion for testing
* purposes. For non-tests, use {@link #upgradeIfNecessaryLP(Bundle)}.
*/
- @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
+ @GuardedBy({"mPackagesLock"})
@VisibleForTesting
void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions, int userVersion,
int userTypeVersion) {
@@ -3255,13 +3389,14 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
}
- @GuardedBy({"mPackagesLock", "mRestrictionsLock"})
+ @GuardedBy({"mPackagesLock"})
private void fallbackToSingleUserLP() {
int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN
| UserInfo.FLAG_PRIMARY;
// Create the system user
- String systemUserType = UserManager.isHeadlessSystemUserMode() ?
- UserManager.USER_TYPE_SYSTEM_HEADLESS : UserManager.USER_TYPE_FULL_SYSTEM;
+ String systemUserType = UserManager.isHeadlessSystemUserMode()
+ ? UserManager.USER_TYPE_SYSTEM_HEADLESS
+ : UserManager.USER_TYPE_FULL_SYSTEM;
flags |= mUserTypes.get(systemUserType).getDefaultUserInfoFlags();
UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags, systemUserType);
UserData userData = putUserInfo(system);
@@ -3325,6 +3460,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @GuardedBy({"mPackagesLock"})
private void writeAllTargetUsersLP(int originatingUserId) {
for (int i = 0; i < mDevicePolicyLocalUserRestrictions.size(); i++) {
int targetUserId = mDevicePolicyLocalUserRestrictions.keyAt(i);
@@ -3335,6 +3471,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @GuardedBy({"mPackagesLock"})
private void writeUserLP(UserData userData) {
if (DBG) {
debug("writeUserLP " + userData);
@@ -3358,6 +3495,7 @@ public class UserManagerService extends IUserManager.Stub {
* <name>Primary</name>
* </user>
*/
+ @GuardedBy({"mPackagesLock"})
@VisibleForTesting
void writeUserLP(UserData userData, OutputStream os)
throws IOException, XmlPullParserException {
@@ -3459,7 +3597,7 @@ public class UserManagerService extends IUserManager.Stub {
* <user id="2"></user>
* </users>
*/
- @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
+ @GuardedBy({"mPackagesLock"})
private void writeUserListLP() {
if (DBG) {
debug("writeUserList");
@@ -3484,7 +3622,9 @@ public class UserManagerService extends IUserManager.Stub {
}
serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
serializer.startTag(null, TAG_DEVICE_OWNER_USER_ID);
- serializer.attributeInt(null, ATTR_ID, mDeviceOwnerUserId);
+ synchronized (mRestrictionsLock) {
+ serializer.attributeInt(null, ATTR_ID, mDeviceOwnerUserId);
+ }
serializer.endTag(null, TAG_DEVICE_OWNER_USER_ID);
int[] userIdsToWrite;
synchronized (mUsersLock) {
@@ -3510,6 +3650,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @GuardedBy({"mPackagesLock"})
private UserData readUserLP(int id) {
FileInputStream fis = null;
try {
@@ -3527,6 +3668,7 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
+ @GuardedBy({"mPackagesLock"})
@VisibleForTesting
UserData readUserLP(int id, InputStream is) throws IOException,
XmlPullParserException {
@@ -3699,6 +3841,7 @@ public class UserManagerService extends IUserManager.Stub {
*
* @return whether there were any restrictions.
*/
+ @GuardedBy({"mAppRestrictionsLock"})
private static boolean cleanAppRestrictionsForPackageLAr(String pkg, @UserIdInt int userId) {
final File dir = Environment.getUserSystemDirectory(userId);
final File resFile = new File(dir, packageToRestrictionsFileName(pkg));
@@ -3984,6 +4127,10 @@ public class UserManagerService extends IUserManager.Stub {
flags &= ~UserInfo.FLAG_EPHEMERAL;
}
+ if ((flags & UserInfo.FLAG_EPHEMERAL) != 0) {
+ flags |= UserInfo.FLAG_EPHEMERAL_ON_CREATE;
+ }
+
userInfo = new UserInfo(userId, name, null, flags, userType);
userInfo.serialNumber = mNextSerialNumber++;
userInfo.creationTime = getCreationTime();
@@ -4235,7 +4382,7 @@ public class UserManagerService extends IUserManager.Stub {
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade,
@Nullable ArraySet<String> existingPackages) {
return mSystemPackageInstaller.installWhitelistedSystemPackages(
- isFirstBoot, isUpgrade, existingPackages);
+ isFirstBoot || mUpdatingSystemUserMode, isUpgrade, existingPackages);
}
@Override
@@ -5479,6 +5626,18 @@ public class UserManagerService extends IUserManager.Stub {
pw.println(" --mode MODE: shows what errors would be if device used mode MODE");
pw.println(" (where MODE is the allowlist mode integer as defined by "
+ "config_userTypePackageWhitelistMode)");
+ pw.println();
+ pw.println(" set-system-user-mode-emulation [--reboot | --no-restart] "
+ + "<headless | full | default>");
+ pw.println(" Changes whether the system user is headless, full, or default (as "
+ + "defined by OEM).");
+ pw.println(" WARNING: this command is meant just for development and debugging "
+ + "purposes.");
+ pw.println(" It should NEVER be used on automated tests.");
+ pw.println(" NOTE: by default it restarts the Android runtime, unless called with");
+ pw.println(" --reboot (which does a full reboot) or");
+ pw.println(" --no-restart (which requires a manual restart)");
+ pw.println();
}
@Override
@@ -5493,6 +5652,8 @@ public class UserManagerService extends IUserManager.Stub {
return runList();
case "report-system-user-package-whitelist-problems":
return runReportPackageAllowlistProblems();
+ case "set-system-user-mode-emulation":
+ return runSetSystemUserModeEmulation();
default:
return handleDefaultCommands(cmd);
}
@@ -5622,6 +5783,141 @@ public class UserManagerService extends IUserManager.Stub {
return 0;
}
+
+ private int runSetSystemUserModeEmulation() {
+ if (!confirmBuildIsDebuggable() || !confirmIsCalledByRoot()) {
+ return -1;
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+
+ // The headless system user cannot be locked; in theory, we could just make this check
+ // when going full -> headless, but it doesn't hurt to check on both (and it makes the
+ // code simpler)
+ if (mLockPatternUtils.isSecure(UserHandle.USER_SYSTEM)) {
+ pw.println("Cannot change system user mode when it has a credential");
+ return -1;
+ }
+
+ boolean restart = true;
+ boolean reboot = false;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--reboot":
+ reboot = true;
+ break;
+ case "--no-restart":
+ restart = false;
+ break;
+ default:
+ pw.println("Invalid option: " + opt);
+ return -1;
+ }
+ }
+ if (reboot && !restart) {
+ getErrPrintWriter().println("You can use --reboot or --no-restart, but not both");
+ return -1;
+ }
+
+ final String mode = getNextArgRequired();
+ final boolean isHeadlessSystemUserModeCurrently = UserManager
+ .isHeadlessSystemUserMode();
+ final boolean changed;
+
+ switch (mode) {
+ case UserManager.SYSTEM_USER_MODE_EMULATION_FULL:
+ changed = isHeadlessSystemUserModeCurrently;
+ break;
+ case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS:
+ changed = !isHeadlessSystemUserModeCurrently;
+ break;
+ case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT:
+ changed = true; // Always update when resetting to default
+ break;
+ default:
+ getErrPrintWriter().printf("Invalid arg: %s\n", mode);
+ return -1;
+ }
+
+ if (!changed) {
+ pw.printf("No change needed, system user is already %s\n",
+ isHeadlessSystemUserModeCurrently ? "headless" : "full");
+ return 0;
+ }
+
+ Slogf.d(LOG_TAG, "Updating system property %s to %s",
+ UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode);
+
+ SystemProperties.set(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode);
+
+ if (reboot) {
+ Slog.i(LOG_TAG, "Rebooting to finalize the changes");
+ pw.println("Rebooting to finalize changes");
+ UiThread.getHandler()
+ .post(() -> ShutdownThread.reboot(
+ ActivityThread.currentActivityThread().getSystemUiContext(),
+ "To switch headless / full system user mode",
+ /* confirm= */ false));
+ } else if (restart) {
+ Slog.i(LOG_TAG, "Shutting PackageManager down");
+ getPackageManagerInternal().shutdown();
+
+ final IActivityManager am = ActivityManager.getService();
+ if (am != null) {
+ try {
+ Slog.i(LOG_TAG, "Shutting ActivityManager down");
+ am.shutdown(/* timeout= */ 10_000);
+ } catch (RemoteException e) {
+ }
+ }
+
+ final int pid = Process.myPid();
+ Slogf.i(LOG_TAG, "Restarting Android runtime(PID=%d) to finalize changes", pid);
+ pw.println("Restarting Android runtime to finalize changes");
+ pw.flush();
+
+ // Ideally there should be a cleaner / safer option to restart system_server, but
+ // that doesn't seems to be the case. For example, ShutdownThread.reboot() calls
+ // pm.shutdown() and am.shutdown() (which we already are calling above), but when
+ // the system is restarted through 'adb shell stop && adb shell start`, these
+ // methods are not called, so just killing the process seems to be fine.
+
+ Process.killProcess(pid);
+ } else {
+ pw.println("System user mode changed - please reboot (or restart Android runtime) "
+ + "to continue");
+ pw.println("NOTICE: after restart, some apps might be uninstalled (and their data "
+ + "will be lost)");
+ }
+ return 0;
+ }
+
+ /**
+ * Confirms if the build is debuggable
+ *
+ * <p>It logs an error when it isn't.
+ */
+ private boolean confirmBuildIsDebuggable() {
+ if (Build.isDebuggable()) {
+ return true;
+ }
+ getErrPrintWriter().println("Command not available on user builds");
+ return false;
+ }
+
+ /**
+ * Confirms if the command is called when {@code adb} is rooted.
+ *
+ * <p>It logs an error when it isn't.
+ */
+ private boolean confirmIsCalledByRoot() {
+ if (Binder.getCallingUid() == Process.ROOT_UID) {
+ return true;
+ }
+ getErrPrintWriter().println("Command only available on root user");
+ return false;
+ }
} // class Shell
@Override
@@ -5661,7 +5957,9 @@ public class UserManagerService extends IUserManager.Stub {
pw.println();
pw.println("Device properties:");
- pw.println(" Device owner id:" + mDeviceOwnerUserId);
+ synchronized (mRestrictionsLock) {
+ pw.println(" Device owner id:" + mDeviceOwnerUserId);
+ }
pw.println();
pw.println(" Guest restrictions:");
synchronized (mGuestRestrictions) {
@@ -5706,7 +6004,14 @@ public class UserManagerService extends IUserManager.Stub {
com.android.internal.R.bool.config_guestUserEphemeral));
pw.println(" Force ephemeral users: " + mForceEphemeralUsers);
pw.println(" Is split-system user: " + UserManager.isSplitSystemUser());
- pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
+ final boolean isHeadlessSystemUserMode = UserManager.isHeadlessSystemUserMode();
+ pw.println(" Is headless-system mode: " + isHeadlessSystemUserMode);
+ if (isHeadlessSystemUserMode != isReallyHeadlessSystemUserMode()) {
+ pw.println(" (emulated by 'cmd user set-system-user-mode-emulation')");
+ if (mUpdatingSystemUserMode) {
+ pw.println(" (and being updated after boot)");
+ }
+ }
pw.println(" User version: " + mUserVersion);
pw.println(" Owner name: " + getOwnerName());
if (DBG_ALLOCATION) {
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 60864a37ef45..937b2cf047a4 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -398,7 +398,7 @@ class UserSystemPackageInstaller {
final String logMessageFmt = "System package %s is not whitelisted using "
+ "'install-in-user-type' in SystemConfig for any user types!";
pmInt.forEachPackage(pkg -> {
- if (!pkg.isSystem()) return;
+ if (!pkg.isSystem() || pkg.isApex()) return;
final String pkgName = pkg.getManifestPackageName();
if (!allWhitelistedPackages.contains(pkgName)
&& !shouldUseOverlayTargetName(pmInt.getPackage(pkgName))) {
@@ -574,7 +574,8 @@ class UserSystemPackageInstaller {
final String pkgName = shouldUseOverlayTargetName(sysPkg) ?
sysPkg.getOverlayTarget() : sysPkg.getManifestPackageName();
return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName))
- || userWhitelist.contains(pkgName);
+ || userWhitelist.contains(pkgName)
+ || sysPkg.isApex();
}
/**
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index cb18c6d83788..0878da49df5b 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -170,9 +170,9 @@ public final class UserTypeFactory {
.setBaseType(FLAG_PROFILE)
.setMaxAllowedPerParent(2)
.setLabel(0)
- .setIconBadge(com.android.internal.R.drawable.ic_corp_icon_badge_case)
- .setBadgePlain(com.android.internal.R.drawable.ic_corp_badge_case)
- .setBadgeNoBackground(com.android.internal.R.drawable.ic_corp_badge_no_background)
+ .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment)
+ .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment)
+ .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background)
.setBadgeLabels(
com.android.internal.R.string.managed_profile_label_badge,
com.android.internal.R.string.managed_profile_label_badge_2,
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index 7423bf65c6a5..0e8b3997da2c 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -123,6 +123,7 @@ final class VerificationParams extends HandlerParams {
final long mRequiredInstalledVersionCode;
final int mDataLoaderType;
final int mSessionId;
+ final boolean mUserActionRequired;
private boolean mWaitForVerificationToComplete;
private boolean mWaitForIntegrityVerificationToComplete;
@@ -135,7 +136,7 @@ final class VerificationParams extends HandlerParams {
VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
- PackageManagerService pm) {
+ boolean userActionRequired, PackageManagerService pm) {
super(user, pm);
mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
mObserver = observer;
@@ -154,6 +155,7 @@ final class VerificationParams extends HandlerParams {
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
mSessionId = sessionId;
mPackageLite = lite;
+ mUserActionRequired = userActionRequired;
}
@Override
@@ -430,6 +432,8 @@ final class VerificationParams extends HandlerParams {
verification.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
+ verification.putExtra(PackageManager.EXTRA_USER_ACTION_REQUIRED, mUserActionRequired);
+
populateInstallerExtras(verification);
// Streaming installation timeout schema is enabled only for:
@@ -579,9 +583,8 @@ final class VerificationParams extends HandlerParams {
}
private boolean packageExists(String packageName) {
- synchronized (mPm.mLock) {
- return mPm.mSettings.getPackageLPr(packageName) != null;
- }
+ Computer snapshot = mPm.snapshotComputer();
+ return snapshot.getPackageStateInternal(packageName) != null;
}
private boolean isAdbVerificationEnabled(PackageInfoLite pkgInfoLite, int userId,
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 8d1bcfcb3938..9c620c4ff3ab 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -121,6 +121,7 @@ public class PackageInfoUtils {
info.isStub = pkg.isStub();
info.coreApp = pkg.isCoreApp();
+ info.isApex = pkg.isApex();
if (pkgSetting != null && !pkgSetting.hasSharedUser()) {
// It is possible that this shared UID app has left
@@ -203,7 +204,8 @@ public class PackageInfoUtils {
info.instrumentation = new InstrumentationInfo[N];
for (int i = 0; i < N; i++) {
info.instrumentation[i] = generateInstrumentationInfo(
- pkg.getInstrumentations().get(i), pkg, flags, userId, pkgSetting);
+ pkg.getInstrumentations().get(i), pkg, flags, state,
+ userId, pkgSetting);
}
}
}
@@ -362,9 +364,12 @@ public class PackageInfoUtils {
*/
@Nullable
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
- AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId,
- @Nullable PackageStateInternal pkgSetting) {
+ AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags,
+ PackageUserStateInternal state, int userId, @Nullable PackageStateInternal pkgSetting) {
if (i == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+ return null;
+ }
InstrumentationInfo info =
PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId,
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index b2e15e7a5bab..e0d5aec65ae7 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -65,8 +65,8 @@ public class PackageParser2 implements AutoCloseable {
public static PackageParser2 forParsingFileWithDefaults() {
IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
- return new PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
- null /* displayMetrics */, null /* cacheDir */, new Callback() {
+ return new PackageParser2(null /* separateProcesses */, null /* displayMetrics */,
+ null /* cacheDir */, new Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
try {
@@ -108,13 +108,8 @@ public class PackageParser2 implements AutoCloseable {
private ParsingPackageUtils parsingUtils;
- /**
- * @param onlyCoreApps Flag indicating this parser should only consider apps with
- * {@code coreApp} manifest attribute to be valid apps. This is useful when
- * creating a minimalist boot environment.
- */
- public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics displayMetrics, @Nullable File cacheDir, @NonNull Callback callback) {
+ public PackageParser2(String[] separateProcesses, DisplayMetrics displayMetrics,
+ @Nullable File cacheDir, @NonNull Callback callback) {
if (displayMetrics == null) {
displayMetrics = new DisplayMetrics();
displayMetrics.setToDefaults();
@@ -127,8 +122,8 @@ public class PackageParser2 implements AutoCloseable {
mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
- parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics,
- splitPermissions, callback);
+ parsingUtils = new ParsingPackageUtils(separateProcesses, displayMetrics, splitPermissions,
+ callback);
ParseInput.Callback enforcementCallback = (changeId, packageName, targetSdkVersion) -> {
ApplicationInfo appInfo = mSharedAppInfo.get();
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 193e1a22d787..b91f15a4d037 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -161,6 +161,7 @@ public class PackageImpl extends ParsingPackageImpl implements ParsedPackage, An
private static final int SIGNED_WITH_PLATFORM_KEY = 1 << 9;
private static final int NATIVE_LIBRARY_ROOT_REQUIRES_ISA = 1 << 10;
private static final int STUB = 1 << 11;
+ private static final int APEX = 1 << 12;
}
private ParsedPackage setBoolean(@Booleans.Flags int flag, boolean value) {
@@ -627,6 +628,11 @@ public class PackageImpl extends ParsingPackageImpl implements ParsedPackage, An
}
@Override
+ public boolean isApex() {
+ return getBoolean(Booleans.APEX);
+ }
+
+ @Override
public boolean isSystemExt() {
return getBoolean(Booleans.SYSTEM_EXT);
}
@@ -694,6 +700,12 @@ public class PackageImpl extends ParsingPackageImpl implements ParsedPackage, An
}
@Override
+ public PackageImpl setApex(boolean isApex) {
+ setBoolean(Booleans.APEX, isApex);
+ return this;
+ }
+
+ @Override
public PackageImpl setSystemExt(boolean value) {
setBoolean(Booleans.SYSTEM_EXT, value);
return this;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index bb08f09d5ab8..38d87e2eef3c 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -66,6 +66,8 @@ public interface ParsedPackage extends AndroidPackage {
ParsedPackage setFactoryTest(boolean factoryTest);
+ ParsedPackage setApex(boolean isApex);
+
ParsedPackage markNotActivitiesAsNotExportedIfSingleUser();
ParsedPackage setOdm(boolean odm);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index cc1c943c2540..a92d35c4dcd7 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -848,7 +848,8 @@ final class DefaultPermissionGrantPolicy {
Intent.CATEGORY_HOME_MAIN, userId);
grantPermissionsToSystemPackage(pm, wearPackage, userId,
CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(pm, wearPackage, userId, PHONE_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, wearPackage, userId, PHONE_PERMISSIONS,
+ ACTIVITY_RECOGNITION_PERMISSIONS);
// Fitness tracking on watches
if (mContext.getResources().getBoolean(R.bool.config_trackerAppNeedsPermissions)) {
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 a83cb5e37ba2..367beb50473f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -275,10 +275,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private boolean checkAutoRevokeAccess(AndroidPackage pkg, int callingUid) {
- if (pkg == null) {
- return false;
- }
-
final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS)
== PackageManager.PERMISSION_GRANTED;
@@ -290,6 +286,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS
+ " or be the installer on record");
}
+
+ if (pkg == null || mPackageManagerInt.filterAppAccess(pkg, callingUid,
+ UserHandle.getUserId(callingUid))) {
+ return false;
+ }
+
return true;
}
@@ -299,9 +301,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
final int callingUid = Binder.getCallingUid();
- if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId)) {
- return false;
- }
if (!checkAutoRevokeAccess(pkg, callingUid)) {
return false;
@@ -781,6 +780,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId) {
mPermissionManagerServiceImpl.resetRuntimePermissions(pkg, userId);
}
+ @Override
+ public void resetRuntimePermissionsForUser(@UserIdInt int userId) {
+ mPermissionManagerServiceImpl.resetRuntimePermissionsForUser(userId);
+ }
@Override
public Permission getPermissionTEMP(String permName) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d34682df3413..d545d41ea326 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -48,7 +48,6 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
-import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
@@ -104,7 +103,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
-import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -610,9 +608,11 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
return null;
}
+ final ParsedPermissionGroup permissionGroup;
final List<PermissionInfo> out = new ArrayList<>(10);
synchronized (mLock) {
- if (groupName != null && mRegistry.getPermissionGroup(groupName) == null) {
+ permissionGroup = mRegistry.getPermissionGroup(groupName);
+ if (groupName != null && permissionGroup == null) {
return null;
}
for (Permission bp : mRegistry.getPermissions()) {
@@ -623,6 +623,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
final int callingUserId = UserHandle.getUserId(callingUid);
+ if (permissionGroup != null && mPackageManagerInt.filterAppAccess(
+ permissionGroup.getPackageName(), callingUid, callingUserId)) {
+ return null;
+ }
out.removeIf(it -> mPackageManagerInt.filterAppAccess(it.packageName, callingUid,
callingUserId));
return out;
@@ -1656,30 +1660,16 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
/**
* Reverts user permission state changes (permissions and flags).
*
- * @param pkg The package for which to reset.
+ * @param filterPkg The package for which to reset, or {@code null} for all packages.
* @param userId The device user for which to do a reset.
*/
- private void resetRuntimePermissionsInternal(@NonNull AndroidPackage pkg,
+ private void resetRuntimePermissionsInternal(@Nullable AndroidPackage filterPkg,
@UserIdInt int userId) {
- final String packageName = pkg.getPackageName();
-
- // These are flags that can change base on user actions.
- final int userSettableMask = FLAG_PERMISSION_USER_SET
- | FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_REVOKED_COMPAT
- | FLAG_PERMISSION_REVIEW_REQUIRED
- | FLAG_PERMISSION_ONE_TIME
- | FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
-
- final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
- | FLAG_PERMISSION_POLICY_FIXED;
-
// Delay and combine non-async permission callbacks
- final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
final boolean[] permissionRemoved = new boolean[1];
final ArraySet<Long> revokedPermissions = new ArraySet<>();
- final IntArray syncUpdatedUsers = new IntArray(permissionCount);
- final IntArray asyncUpdatedUsers = new IntArray(permissionCount);
+ final ArraySet<Integer> syncUpdatedUsers = new ArraySet<>();
+ final ArraySet<Integer> asyncUpdatedUsers = new ArraySet<>();
PermissionCallback delayingPermCallback = new PermissionCallback() {
public void onGidsChanged(int appId, int userId) {
@@ -1741,6 +1731,55 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
};
+ if (filterPkg != null) {
+ resetRuntimePermissionsInternal(filterPkg, userId, delayingPermCallback);
+ } else {
+ mPackageManagerInt.forEachPackage(pkg ->
+ resetRuntimePermissionsInternal(pkg, userId, delayingPermCallback));
+ }
+
+ // Execute delayed callbacks
+ if (permissionRemoved[0]) {
+ mDefaultPermissionCallback.onPermissionRemoved();
+ }
+
+ // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
+ // kill uid while holding mPackages-lock
+ if (!revokedPermissions.isEmpty()) {
+ int numRevokedPermissions = revokedPermissions.size();
+ for (int i = 0; i < numRevokedPermissions; i++) {
+ int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
+ int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
+
+ mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
+
+ // Kill app later as we are holding mPackages
+ mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
+ KILL_APP_REASON_PERMISSIONS_REVOKED));
+ }
+ }
+
+ mPackageManagerInt.writePermissionSettings(ArrayUtils.convertToIntArray(syncUpdatedUsers),
+ false);
+ mPackageManagerInt.writePermissionSettings(ArrayUtils.convertToIntArray(asyncUpdatedUsers),
+ true);
+ }
+
+ private void resetRuntimePermissionsInternal(@NonNull AndroidPackage pkg,
+ @UserIdInt int userId, @NonNull PermissionCallback delayingPermCallback) {
+ // These are flags that can change base on user actions.
+ final int userSettableMask = FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED
+ | FLAG_PERMISSION_REVOKED_COMPAT
+ | FLAG_PERMISSION_REVIEW_REQUIRED
+ | FLAG_PERMISSION_ONE_TIME
+ | FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
+
+ final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
+ | FLAG_PERMISSION_POLICY_FIXED;
+
+ final String packageName = pkg.getPackageName();
+ final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
for (int i = 0; i < permissionCount; i++) {
final String permName = pkg.getRequestedPermissions().get(i);
@@ -1819,30 +1858,6 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
userId, null, delayingPermCallback);
}
}
-
- // Execute delayed callbacks
- if (permissionRemoved[0]) {
- mDefaultPermissionCallback.onPermissionRemoved();
- }
-
- // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
- // kill uid while holding mPackages-lock
- if (!revokedPermissions.isEmpty()) {
- int numRevokedPermissions = revokedPermissions.size();
- for (int i = 0; i < numRevokedPermissions; i++) {
- int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
- int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
-
- mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
-
- // Kill app later as we are holding mPackages
- mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
- KILL_APP_REASON_PERMISSIONS_REVOKED));
- }
- }
-
- mPackageManagerInt.writePermissionSettings(syncUpdatedUsers.toArray(), false);
- mPackageManagerInt.writePermissionSettings(asyncUpdatedUsers.toArray(), true);
}
/**
@@ -2488,13 +2503,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
* @param pkg the package the permissions belong to
* @param replace if the package is getting replaced (this might change the requested
* permissions of this package)
- * @param packageOfInterest If this is the name of {@code pkg} add extra logging
+ * @param changingPackageName the name of the package that is changing
* @param callback Result call back
* @param filterUserId If not {@link UserHandle.USER_ALL}, only restore the permission state for
* this particular user
*/
private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
- @Nullable String packageOfInterest, @Nullable PermissionCallback callback,
+ @Nullable String changingPackageName, @Nullable PermissionCallback callback,
@UserIdInt int filterUserId) {
// IMPORTANT: There are two types of permissions: install and runtime.
// Install time permissions are granted when the app is installed to
@@ -2516,6 +2531,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
final int[] userIds = filterUserId == UserHandle.USER_ALL ? getAllUserIds()
: new int[] { filterUserId };
+ boolean installPermissionsChanged = false;
boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;
@@ -2634,7 +2650,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
UidPermissionState origState = uidState;
- boolean changedInstallPermission = false;
+ boolean installPermissionsChangedForUser = false;
if (replace) {
userState.setInstallPermissionsFixed(ps.getPackageName(), false);
@@ -2675,7 +2691,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
// permission is present, because otherwise the permission should have been
// removed.
if (bp == null /*|| getSourcePackageSetting(bp) == null*/) {
- if (packageOfInterest == null || packageOfInterest.equals(
+ if (changingPackageName == null || changingPackageName.equals(
pkg.getPackageName())) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Unknown permission " + permName
@@ -2800,7 +2816,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
&& origState.isPermissionGranted(permName))))) {
// Grant an install permission.
if (uidState.grantPermission(bp)) {
- changedInstallPermission = true;
+ installPermissionsChangedForUser = true;
}
} else if (bp.isRuntime()) {
boolean hardRestricted = bp.isHardRestricted();
@@ -2940,12 +2956,12 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
if (uidState.removePermissionState(bp.getName())) {
- changedInstallPermission = true;
+ installPermissionsChangedForUser = true;
}
}
}
- if ((changedInstallPermission || replace)
+ if ((installPermissionsChangedForUser || replace)
&& !userState.areInstallPermissionsFixed(ps.getPackageName())
&& !ps.isSystem() || ps.getTransientState().isUpdatedSystemApp()) {
// This is the first that we have heard about this package, so the
@@ -2954,6 +2970,12 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
userState.setInstallPermissionsFixed(ps.getPackageName(), true);
}
+ if (installPermissionsChangedForUser) {
+ installPermissionsChanged = true;
+ if (changingPackageName != null && replace) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+ }
updatedUserIds = revokePermissionsNoLongerImplicitLocked(uidState,
pkg.getPackageName(), uidImplicitPermissions, uidTargetSdkVersion, userId,
updatedUserIds);
@@ -2970,8 +2992,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
// Persist the runtime permissions state for users with changes. If permissions
// were revoked because no app in the shared user declares them we have to
// write synchronously to avoid losing runtime permissions state.
+ // Also write synchronously if we changed any install permission for an updated app, because
+ // the install permission state is likely already fixed before update, and if we lose the
+ // changes here the app won't be reconsidered for newly-added install permissions.
if (callback != null) {
- callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked);
+ callback.onPermissionUpdated(updatedUserIds,
+ (changingPackageName != null && replace && installPermissionsChanged)
+ || runtimePermissionsRevoked);
}
for (int userId : updatedUserIds) {
@@ -3297,9 +3324,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
// Only enforce the allowlist on boot
if (!mSystemReady) {
- final boolean isInUpdatedApex = containingApexPackageName != null
- && !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
- MATCH_ACTIVE_PACKAGE));
+ final boolean isInUpdatedApex = packageSetting.isApkInUpdatedApex();
// Apps that are in updated apexs' do not need to be allowlisted
if (!isInUpdatedApex) {
Slog.w(TAG, "Privileged permission " + permissionName + " for package "
@@ -5175,6 +5200,12 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
+ public void resetRuntimePermissionsForUser(@UserIdInt int userId) {
+ Preconditions.checkArgumentNonNegative(userId, "userId");
+ resetRuntimePermissionsInternal(null, userId);
+ }
+
+ @Override
public Permission getPermissionTEMP(String permName) {
synchronized (mLock) {
return mRegistry.getPermission(permName);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3771f030aefa..02d184e2b1e0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -428,6 +428,13 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
@UserIdInt int userId);
/**
+ * Reset the runtime permission state changes for all packages in a user.
+ *
+ * @param userId the user ID
+ */
+ void resetRuntimePermissionsForUser(@UserIdInt int userId);
+
+ /**
* Read legacy permission state from package settings.
*
* TODO(zhanghai): This is a temporary method because we should not expose
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index d2c4ec4cc5a5..67d51813778c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -102,6 +102,14 @@ public interface PermissionManagerServiceInternal extends PermissionManagerInter
@UserIdInt int userId);
/**
+ * Reset the runtime permission state changes for all packages in a user.
+ *
+ * @param userId the user ID
+ */
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ void resetRuntimePermissionsForUser(@UserIdInt int userId);
+
+ /**
* Read legacy permission state from package settings.
*
* TODO(zhanghai): This is a temporary method because we should not expose
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java b/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
index a0bb8dc48ecf..a529abbfadf5 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
@@ -331,6 +331,8 @@ public interface AndroidPackageApi {
boolean isFactoryTest();
+ boolean isApex();
+
boolean isNativeLibraryRootRequiresIsa();
boolean isOdm();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 7726d7fc226b..b5e0e4416fe4 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -303,6 +303,11 @@ public interface PackageState {
boolean isUpdatedSystemApp();
/**
+ * Whether this app is packaged in an updated apex.
+ */
+ boolean isApkInUpdatedApex();
+
+ /**
* @see AndroidPackageApi#isVendor()
*/
boolean isVendor();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 3170304985b5..878a837585ca 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -71,6 +71,7 @@ public class PackageStateImpl implements PackageState {
INSTALL_PERMISSIONS_FIXED,
UPDATE_AVAILABLE,
UPDATED_SYSTEM_APP,
+ APK_IN_UPDATED_APEX,
})
public @interface Flags {
}
@@ -89,6 +90,7 @@ public class PackageStateImpl implements PackageState {
private static final int INSTALL_PERMISSIONS_FIXED = 1 << 11;
private static final int UPDATE_AVAILABLE = 1 << 12;
private static final int UPDATED_SYSTEM_APP = 1 << 13;
+ private static final int APK_IN_UPDATED_APEX = 1 << 14;
}
private int mBooleans;
@@ -187,6 +189,7 @@ public class PackageStateImpl implements PackageState {
setBoolean(Booleans.UPDATE_AVAILABLE, pkgState.isUpdateAvailable());
mLastPackageUsageTime = pkgState.getLastPackageUsageTime();
setBoolean(Booleans.UPDATED_SYSTEM_APP, pkgState.isUpdatedSystemApp());
+ setBoolean(Booleans.APK_IN_UPDATED_APEX, pkgState.isApkInUpdatedApex());
mSigningInfo = pkgState.getSigningInfo();
SparseArray<? extends PackageUserState> userStates = pkgState.getUserStates();
@@ -264,6 +267,11 @@ public class PackageStateImpl implements PackageState {
}
@Override
+ public boolean isApkInUpdatedApex() {
+ return getBoolean(Booleans.APK_IN_UPDATED_APEX);
+ }
+
+ @Override
public boolean isVendor() {
return getBoolean(Booleans.VENDOR);
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index 7bd720acc799..fad2f857f656 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -52,6 +52,8 @@ public class PackageStateUnserialized {
private List<String> usesLibraryFiles = emptyList();
private boolean updatedSystemApp;
+ private boolean apkInApex;
+ private boolean apkInUpdatedApex;
@NonNull
private volatile long[] lastPackageUsageTimeInMills;
@@ -116,6 +118,8 @@ public class PackageStateUnserialized {
}
this.updatedSystemApp = other.updatedSystemApp;
+ this.apkInApex = other.apkInApex;
+ this.apkInUpdatedApex = other.apkInUpdatedApex;
this.lastPackageUsageTimeInMills = other.lastPackageUsageTimeInMills;
this.overrideSeInfo = other.overrideSeInfo;
mPackageSetting.onChanged();
@@ -150,6 +154,18 @@ public class PackageStateUnserialized {
return this;
}
+ public PackageStateUnserialized setApkInApex(boolean value) {
+ apkInApex = value;
+ mPackageSetting.onChanged();
+ return this;
+ }
+
+ public PackageStateUnserialized setApkInUpdatedApex(boolean value) {
+ apkInUpdatedApex = value;
+ mPackageSetting.onChanged();
+ return this;
+ }
+
public PackageStateUnserialized setLastPackageUsageTimeInMills(@NonNull long... value) {
lastPackageUsageTimeInMills = value;
mPackageSetting.onChanged();
@@ -198,6 +214,16 @@ public class PackageStateUnserialized {
}
@DataClass.Generated.Member
+ public boolean isApkInApex() {
+ return apkInApex;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isApkInUpdatedApex() {
+ return apkInUpdatedApex;
+ }
+
+ @DataClass.Generated.Member
public @NonNull long[] getLastPackageUsageTimeInMills() {
long[] _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills;
if (_lastPackageUsageTimeInMills == null) {
@@ -222,10 +248,10 @@ public class PackageStateUnserialized {
}
@DataClass.Generated(
- time = 1642554781099L,
+ time = 1646203523807L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java",
- inputSignatures = "private boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate boolean updatedSystemApp\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\nprivate long[] lazyInitLastPackageUsageTimeInMills()\npublic com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic long getLatestPackageUseTimeInMills()\npublic long getLatestForegroundPackageUseTimeInMills()\npublic void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
+ inputSignatures = "private boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate boolean updatedSystemApp\nprivate boolean apkInApex\nprivate boolean apkInUpdatedApex\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate final @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\nprivate long[] lazyInitLastPackageUsageTimeInMills()\npublic com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic long getLatestPackageUseTimeInMills()\npublic long getLatestForegroundPackageUseTimeInMills()\npublic void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setApkInApex(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setApkInUpdatedApex(boolean)\npublic com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
index 281e1bd2824d..10e8c47f7b1a 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
@@ -25,6 +25,7 @@ import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Slog;
@@ -55,8 +56,7 @@ public class ParsedPermissionUtils {
String tag = "<" + parser.getName() + ">";
ParseResult<ParsedPermissionImpl> result;
- TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
- try {
+ try (TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission)) {
result = ParsedComponentUtils.parseComponent(
permission, tag, pkg, sa, useRoundIcon, input,
R.styleable.AndroidManifestPermission_banner,
@@ -70,6 +70,11 @@ public class ParsedPermissionUtils {
return input.error(result);
}
+ int maxSdkVersion = sa.getInt(R.styleable.AndroidManifestPermission_maxSdkVersion, -1);
+ if ((maxSdkVersion != -1) && (maxSdkVersion < Build.VERSION.SDK_INT)) {
+ return input.success(null);
+ }
+
if (sa.hasValue(
R.styleable.AndroidManifestPermission_backgroundPermission)) {
if ("android".equals(packageName)) {
@@ -137,8 +142,6 @@ public class ParsedPermissionUtils {
+ " restricted: " + permission.getName());
}
}
- } finally {
- sa.recycle();
}
permission.setProtectionLevel(
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index b7fde436c8ea..ee59810134f0 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -321,19 +321,15 @@ public class PackageInfoWithoutStateUtils {
pi.applicationInfo.sourceDir = apexFile.getPath();
pi.applicationInfo.publicSourceDir = apexFile.getPath();
+ pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
if (apexInfo.isFactory) {
- pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
} else {
- pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
pi.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- if (apexInfo.isActive) {
- pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
- } else {
- pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
- }
pi.isApex = true;
+ pi.isActiveApex = apexInfo.isActive;
}
final SigningDetails signingDetails = pkg.getSigningDetails();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 06a54a461d5e..6e4acde501c3 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -23,7 +23,6 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFES
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.os.Build.VERSION_CODES.DONUT;
@@ -283,7 +282,7 @@ public class ParsingPackageUtils {
boolean collectCertificates) {
ParseResult<ParsingPackage> result;
- ParsingPackageUtils parser = new ParsingPackageUtils(false, null /*separateProcesses*/,
+ ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/,
null /*displayMetrics*/, splitPermissions, new Callback() {
@Override
public boolean hasFeature(String feature) {
@@ -324,18 +323,15 @@ public class ParsingPackageUtils {
return input.success(pkg);
}
- private boolean mOnlyCoreApps;
private String[] mSeparateProcesses;
private DisplayMetrics mDisplayMetrics;
@NonNull
private List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
private Callback mCallback;
- public ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses,
- DisplayMetrics displayMetrics,
+ public ParsingPackageUtils(String[] separateProcesses, DisplayMetrics displayMetrics,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
@NonNull Callback callback) {
- mOnlyCoreApps = onlyCoreApps;
mSeparateProcesses = separateProcesses;
mDisplayMetrics = displayMetrics;
mSplitPermissionInfos = splitPermissions;
@@ -403,11 +399,6 @@ public class ParsingPackageUtils {
}
final PackageLite lite = liteResult.getResult();
- if (mOnlyCoreApps && !lite.isCoreApp()) {
- return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
- "Not a coreApp: " + packageDir);
- }
-
// Build the split dependency tree.
SparseArray<int[]> splitDependencies = null;
final SplitAssetLoader assetLoader;
@@ -475,11 +466,6 @@ public class ParsingPackageUtils {
}
final PackageLite lite = liteResult.getResult();
- if (mOnlyCoreApps && !lite.isCoreApp()) {
- return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
- "Not a coreApp: " + apkFile);
- }
-
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
final ParseResult<ParsingPackage> result = parseBaseApk(input,
@@ -1248,7 +1234,11 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
- return input.success(pkg.addPermission(result.getResult()));
+ ParsedPermission permission = result.getResult();
+ if (permission != null) {
+ pkg.addPermission(permission);
+ }
+ return input.success(pkg);
}
private static ParseResult<ParsingPackage> parsePermissionTree(ParseInput input,
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index b9bd9f132dbc..ca2897eb4b6e 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -137,20 +137,27 @@ final class GlobalKeyManager {
String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
String dispatchWhenNonInteractive =
parser.getAttributeValue(null, ATTR_DISPATCH_WHEN_NON_INTERACTIVE);
+ if (keyCodeName == null || componentName == null) {
+ Log.wtf(TAG, "Failed to parse global keys entry: " + parser.getText());
+ continue;
+ }
int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
mKeyMapping.put(keyCode, new GlobalKeyAction(
componentName, dispatchWhenNonInteractive));
+ } else {
+ Log.wtf(TAG, "Global keys entry does not map to a valid key code: "
+ + keyCodeName);
}
}
}
}
} catch (Resources.NotFoundException e) {
- Log.w(TAG, "global keys file not found", e);
+ Log.wtf(TAG, "global keys file not found", e);
} catch (XmlPullParserException e) {
- Log.w(TAG, "XML parser exception reading global keys file", e);
+ Log.wtf(TAG, "XML parser exception reading global keys file", e);
} catch (IOException e) {
- Log.w(TAG, "I/O exception reading global keys file", e);
+ Log.e(TAG, "I/O exception reading global keys file", e);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d8e7fbe8b296..d88949bcc0ec 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -169,7 +169,6 @@ import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.IDisplayFoldListener;
-import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.FallbackAction;
@@ -381,7 +380,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private final SparseArray<ScreenOnListener> mScreenOnListeners = new SparseArray<>();
Context mContext;
- IWindowManager mWindowManager;
WindowManagerFuncs mWindowManagerFuncs;
WindowManagerInternal mWindowManagerInternal;
PowerManager mPowerManager;
@@ -1870,10 +1868,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public void init(Context context, IWindowManager windowManager,
- WindowManagerFuncs windowManagerFuncs) {
+ public void init(Context context, WindowManagerFuncs windowManagerFuncs) {
mContext = context;
- mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -4534,7 +4530,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pmWakeReason)) + ")");
}
- mActivityTaskManagerInternal.notifyWakingUp();
mDefaultDisplayPolicy.setAwake(true);
// Since goToSleep performs these functions synchronously, we must
@@ -4802,10 +4797,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (enableScreen) {
- try {
- mWindowManager.enableScreenIfNeeded();
- } catch (RemoteException unhandled) {
- }
+ mWindowManagerFuncs.enableScreenIfNeeded();
}
}
@@ -5262,12 +5254,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
void updateRotation(boolean alwaysSendConfiguration) {
- try {
- // Set orientation on WindowManager.
- mWindowManager.updateRotation(alwaysSendConfiguration, false /* forceRelayout */);
- } catch (RemoteException e) {
- // Ignore
- }
+ mWindowManagerFuncs.updateRotation(alwaysSendConfiguration, false /* forceRelayout */);
}
/**
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 7ca09ab5154f..9bc0553a7612 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -78,7 +78,6 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.IDisplayFoldListener;
-import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -156,6 +155,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
int FINISH_LAYOUT_REDO_ANIM = 0x0008;
/** Layer for the screen off animation */
int COLOR_FADE_LAYER = 0x40000001;
+ /** Layer for Input overlays for capturing inputs for gesture detection, etc. */
+ int INPUT_DISPLAY_OVERLAY_LAYER = 0x7f000000;
+ /** Layer for Screen Decoration: The top most visible layer just below input overlay layers */
+ int SCREEN_DECOR_DISPLAY_OVERLAY_LAYER = INPUT_DISPLAY_OVERLAY_LAYER - 1;
/**
* Register shortcuts for window manager to dispatch.
@@ -343,6 +346,22 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* @return {@code true} if app transition state is idle on the default display.
*/
boolean isAppTransitionStateIdle();
+
+ /**
+ * Enables the screen if all conditions are met.
+ */
+ void enableScreenIfNeeded();
+
+ /**
+ * Updates the current screen rotation based on the current state of the world.
+ *
+ * @param alwaysSendConfiguration Flag to force a new configuration to be evaluated.
+ * This can be used when there are other parameters in
+ * configuration that are changing.
+ * @param forceRelayout If true, the window manager will always do a relayout of its
+ * windows even if the rotation hasn't changed.
+ */
+ void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout);
}
/**
@@ -391,8 +410,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*
* @param context The system context we are running in.
*/
- public void init(Context context, IWindowManager windowManager,
- WindowManagerFuncs windowManagerFuncs);
+ void init(Context context, WindowManagerFuncs windowManagerFuncs);
/**
* Check permissions when adding a window.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3c13abf4403c..c56369e41b23 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -110,6 +110,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.LatencyTracker;
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
@@ -4951,6 +4952,7 @@ public final class PowerManagerService extends SystemService
int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
Intent.EXTRA_DOCK_STATE_UNDOCKED);
if (mDockState != dockState) {
+ FrameworkStatsLog.write(FrameworkStatsLog.DOCK_STATE_CHANGED, dockState);
mDockState = dockState;
mDirty |= DIRTY_DOCK_STATE;
updatePowerStateLocked();
diff --git a/services/core/java/com/android/server/power/ShutdownCheckPoints.java b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
index 05ee7dfb4cae..1a9eae6b6d8d 100644
--- a/services/core/java/com/android/server/power/ShutdownCheckPoints.java
+++ b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
@@ -36,7 +36,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.LinkedList;
import java.util.List;
/**
@@ -56,7 +55,7 @@ public final class ShutdownCheckPoints {
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
- private final LinkedList<CheckPoint> mCheckPoints;
+ private final ArrayList<CheckPoint> mCheckPoints;
private final Injector mInjector;
private ShutdownCheckPoints() {
@@ -85,7 +84,7 @@ public final class ShutdownCheckPoints {
@VisibleForTesting
ShutdownCheckPoints(Injector injector) {
- mCheckPoints = new LinkedList<>();
+ mCheckPoints = new ArrayList<>();
mInjector = injector;
}
@@ -144,8 +143,8 @@ public final class ShutdownCheckPoints {
private void recordCheckPointInternal(CheckPoint checkPoint) {
synchronized (mCheckPoints) {
- mCheckPoints.addLast(checkPoint);
- if (mCheckPoints.size() > mInjector.maxCheckPoints()) mCheckPoints.removeFirst();
+ mCheckPoints.add(checkPoint);
+ if (mCheckPoints.size() > mInjector.maxCheckPoints()) mCheckPoints.remove(0);
}
}
diff --git a/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java b/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java
index 3543e9319a88..928d128d6d16 100644
--- a/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java
+++ b/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java
@@ -32,6 +32,7 @@ import com.android.internal.org.bouncycastle.asn1.ASN1Set;
import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
@@ -147,7 +148,7 @@ class AndroidKeystoreAttestationVerificationAttributes {
@NonNull
static AndroidKeystoreAttestationVerificationAttributes fromCertificate(
@NonNull X509Certificate x509Certificate)
- throws Exception {
+ throws CertificateEncodingException, IOException {
return new AndroidKeystoreAttestationVerificationAttributes(x509Certificate);
}
@@ -281,7 +282,7 @@ class AndroidKeystoreAttestationVerificationAttributes {
}
private AndroidKeystoreAttestationVerificationAttributes(X509Certificate x509Certificate)
- throws Exception {
+ throws CertificateEncodingException, IOException {
Certificate certificate = Certificate.getInstance(
new ASN1InputStream(x509Certificate.getEncoded()).readObject());
ASN1Sequence keyAttributes = (ASN1Sequence) certificate.getTBSCertificate().getExtensions()
@@ -380,7 +381,7 @@ class AndroidKeystoreAttestationVerificationAttributes {
}
private void parseAttestationApplicationId(byte [] attestationApplicationId)
- throws Exception {
+ throws IOException {
ASN1Sequence outerSequence = ASN1Sequence.getInstance(
new ASN1InputStream(attestationApplicationId).readObject());
Map<String, Long> packageNameVersion = new HashMap<>();
diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
index 0f8be5a77944..bcc39ba1bde1 100644
--- a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
+++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
@@ -22,8 +22,10 @@ import static android.security.attestationverification.AttestationVerificationMa
import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS;
import static android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE;
import static android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY;
+import static android.security.attestationverification.AttestationVerificationManager.localBindingTypeToString;
import static com.android.server.security.AndroidKeystoreAttestationVerificationAttributes.VerifiedBootState.VERIFIED;
+import static com.android.server.security.AndroidKeystoreAttestationVerificationAttributes.fromCertificate;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -31,6 +33,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
+import android.security.attestationverification.AttestationVerificationManager.LocalBindingType;
import android.util.Log;
import android.util.Slog;
@@ -40,8 +43,10 @@ import com.android.internal.annotations.VisibleForTesting;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.security.InvalidAlgorithmParameterException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
@@ -65,17 +70,26 @@ import java.util.Objects;
import java.util.Set;
/**
- * Verifies Android key attestation according to the {@code PROFILE_PEER_DEVICE} profile.
+ * Verifies Android key attestation according to the
+ * {@link android.security.attestationverification.AttestationVerificationManager#PROFILE_PEER_DEVICE PROFILE_PEER_DEVICE}
+ * profile.
*
- * Trust anchors are vendor-defined via the vendor_required_attestation_certificates.xml resource.
+ * <p>
* The profile is satisfied by checking all the following:
- * * TrustAnchor match
- * * Certificate validity
- * * Android OS 10 or higher
- * * Hardware backed key store
- * * Verified boot locked
- * * Remote Patch level must be within 1 year of local patch if local patch is less than 1 year old.
+ * <ul>
+ * <li> TrustAnchor match
+ * <li> Certificate validity
+ * <li> Android OS 10 or higher
+ * <li> Hardware backed key store
+ * <li> Verified boot locked
+ * <li> Remote Patch level must be within 1 year of local patch if local patch is less than 1 year
+ * old.
+ * </ul>
*
+ * <p>
+ * Trust anchors are vendor-defined by populating
+ * {@link R.array#vendor_required_attestation_certificates} string array (defenined in
+ * {@code frameworks/base/core/res/res/values/vendor_required_attestation_certificates.xml}).
*/
class AttestationVerificationPeerDeviceVerifier {
private static final String TAG = "AVF";
@@ -87,20 +101,8 @@ class AttestationVerificationPeerDeviceVerifier {
private final boolean mRevocationEnabled;
private final LocalDate mTestSystemDate;
private final LocalDate mTestLocalPatchDate;
- private CertificateFactory mCertificateFactory;
- private CertPathValidator mCertPathValidator;
-
- private static void debugVerboseLog(String str, Throwable t) {
- if (DEBUG) {
- Slog.v(TAG, str, t);
- }
- }
-
- private static void debugVerboseLog(String str) {
- if (DEBUG) {
- Slog.v(TAG, str);
- }
- }
+ private final CertificateFactory mCertificateFactory;
+ private final CertPathValidator mCertPathValidator;
AttestationVerificationPeerDeviceVerifier(@NonNull Context context) throws Exception {
mContext = Objects.requireNonNull(context);
@@ -128,53 +130,71 @@ class AttestationVerificationPeerDeviceVerifier {
/**
* Verifies attestation for public key or challenge local binding.
- *
+ * <p>
* The attestations must be suitable for {@link java.security.cert.CertificateFactory}
* The certificates in the attestation provided must be DER-encoded and may be supplied in
* binary or printable (Base64) encoding. If the certificate is provided in Base64 encoding,
- * it must be bounded at the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
- * the end by -----END CERTIFICATE-----.
+ * it must be bounded at the beginning by {@code -----BEGIN CERTIFICATE-----}, and must be
+ * bounded at the end by {@code -----END CERTIFICATE-----}.
*
* @param localBindingType Only {@code TYPE_PUBLIC_KEY} and {@code TYPE_CHALLENGE} supported.
* @param requirements Only {@code PARAM_PUBLIC_KEY} and {@code PARAM_CHALLENGE} supported.
* @param attestation Certificates should be DER encoded with leaf certificate appended first.
*/
int verifyAttestation(
- int localBindingType, @NonNull Bundle requirements, @NonNull byte[] attestation) {
- int status = RESULT_FAILURE;
-
+ @LocalBindingType int localBindingType,
+ @NonNull Bundle requirements,
+ @NonNull byte[] attestation) {
if (mCertificateFactory == null) {
- debugVerboseLog("Was unable to initialize CertificateFactory onCreate.");
- return status;
+ debugVerboseLog("Unable to access CertificateFactory");
+ return RESULT_FAILURE;
}
if (mCertPathValidator == null) {
- debugVerboseLog("Was unable to initialize CertPathValidator onCreate.");
- return status;
+ debugVerboseLog("Unable to access CertPathValidator");
+ return RESULT_FAILURE;
}
- List<X509Certificate> certificates;
- try {
- certificates = getCertificates(attestation);
- } catch (CertificateException e) {
- debugVerboseLog("Unable to parse attestation certificates.", e);
- return status;
+ // Check if the provided local binding type is supported and if the provided requirements
+ // "match" the binding type.
+ if (!validateAttestationParameters(localBindingType, requirements)) {
+ return RESULT_FAILURE;
}
- if (certificates.isEmpty()) {
- debugVerboseLog("Attestation contains no certificates.");
- return status;
- }
+ try {
+ // First: parse and validate the certificate chain.
+ final List<X509Certificate> certificateChain = getCertificates(attestation);
+ // (returns void, but throws CertificateException and other similar Exceptions)
+ validateCertificateChain(certificateChain);
- X509Certificate leafNode = certificates.get(0);
- if (validateRequirements(localBindingType, requirements)
- && validateCertificateChain(certificates)
- && checkCertificateAttributes(leafNode, localBindingType, requirements)) {
- status = RESULT_SUCCESS;
- } else {
- status = RESULT_FAILURE;
+ final var leafCertificate = certificateChain.get(0);
+ final var attestationExtension = fromCertificate(leafCertificate);
+
+ // Second: verify if the attestation satisfies the "peer device" porfile.
+ if (!checkAttestationForPeerDeviceProfile(attestationExtension)) {
+ return RESULT_FAILURE;
+ }
+
+ // Third: check if the attestation satisfies local binding requirements.
+ if (!checkLocalBindingRequirements(
+ leafCertificate, attestationExtension, localBindingType, requirements)) {
+ return RESULT_FAILURE;
+ }
+
+ return RESULT_SUCCESS;
+ } catch (CertificateException | CertPathValidatorException
+ | InvalidAlgorithmParameterException | IOException e) {
+ // Catch all non-RuntimeExpceptions (all of these are thrown by either getCertificates()
+ // or validateCertificateChain() or
+ // AndroidKeystoreAttestationVerificationAttributes.fromCertificate())
+ debugVerboseLog("Unable to parse/validate Android Attestation certificate(s)", e);
+ return RESULT_FAILURE;
+ } catch (RuntimeException e) {
+ // Catch everyting else (RuntimeExpcetions), since we don't want to throw any exceptions
+ // out of this class/method.
+ debugVerboseLog("Unexpected error", e);
+ return RESULT_FAILURE;
}
- return status;
}
@NonNull
@@ -189,14 +209,19 @@ class AttestationVerificationPeerDeviceVerifier {
return certificates;
}
- private boolean validateRequirements(int localBindingType, Bundle requirements) {
- if (requirements.size() != 1) {
- debugVerboseLog("Requirements does not contain exactly 1 key.");
+ /**
+ * Check if the {@code localBindingType} is supported and if the {@code requirements} contains
+ * the required parameter for the given {@code @LocalBindingType}.
+ */
+ private boolean validateAttestationParameters(
+ @LocalBindingType int localBindingType, @NonNull Bundle requirements) {
+ if (localBindingType != TYPE_PUBLIC_KEY && localBindingType != TYPE_CHALLENGE) {
+ debugVerboseLog("Binding type is not supported: " + localBindingType);
return false;
}
- if (localBindingType != TYPE_PUBLIC_KEY && localBindingType != TYPE_CHALLENGE) {
- debugVerboseLog("Binding type is not supported: " + localBindingType);
+ if (requirements.size() != 1) {
+ debugVerboseLog("Requirements does not contain exactly 1 key.");
return false;
}
@@ -213,29 +238,25 @@ class AttestationVerificationPeerDeviceVerifier {
return true;
}
- private boolean validateCertificateChain(List<X509Certificate> certificates) {
+ private void validateCertificateChain(List<X509Certificate> certificates)
+ throws CertificateException, CertPathValidatorException,
+ InvalidAlgorithmParameterException {
if (certificates.size() < 2) {
debugVerboseLog("Certificate chain less than 2 in size.");
- return false;
+ throw new CertificateException("Certificate chain less than 2 in size.");
}
- try {
- CertPath certificatePath = mCertificateFactory.generateCertPath(certificates);
- PKIXParameters validationParams = new PKIXParameters(mTrustAnchors);
- if (mRevocationEnabled) {
- // Checks Revocation Status List based on
- // https://developer.android.com/training/articles/security-key-attestation#certificate_status
- PKIXCertPathChecker checker = new AndroidRevocationStatusListChecker();
- validationParams.addCertPathChecker(checker);
- }
- // Do not use built-in revocation status checker.
- validationParams.setRevocationEnabled(false);
- mCertPathValidator.validate(certificatePath, validationParams);
- } catch (Throwable t) {
- debugVerboseLog("Invalid certificate chain.", t);
- return false;
+ CertPath certificatePath = mCertificateFactory.generateCertPath(certificates);
+ PKIXParameters validationParams = new PKIXParameters(mTrustAnchors);
+ if (mRevocationEnabled) {
+ // Checks Revocation Status List based on
+ // https://developer.android.com/training/articles/security-key-attestation#certificate_status
+ PKIXCertPathChecker checker = new AndroidRevocationStatusListChecker();
+ validationParams.addCertPathChecker(checker);
}
- return true;
+ // Do not use built-in revocation status checker.
+ validationParams.setRevocationEnabled(false);
+ mCertPathValidator.validate(certificatePath, validationParams);
}
private Set<TrustAnchor> getTrustAnchors() throws CertPathValidatorException {
@@ -267,18 +288,44 @@ class AttestationVerificationPeerDeviceVerifier {
R.array.vendor_required_attestation_certificates);
}
- private boolean checkCertificateAttributes(
- X509Certificate leafCertificate, int localBindingType, Bundle requirements) {
- AndroidKeystoreAttestationVerificationAttributes attestationAttributes;
- try {
- attestationAttributes =
- AndroidKeystoreAttestationVerificationAttributes.fromCertificate(
- leafCertificate);
- } catch (Throwable t) {
- debugVerboseLog("Could not get ParsedAttestationAttributes from Certificate.", t);
- return false;
+ private boolean checkLocalBindingRequirements(
+ @NonNull X509Certificate leafCertificate,
+ @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes,
+ @LocalBindingType int localBindingType,
+ @NonNull Bundle requirements) {
+ switch (localBindingType) {
+ case TYPE_PUBLIC_KEY:
+ // Verify leaf public key matches provided public key.
+ final boolean publicKeyMatches = checkPublicKey(
+ leafCertificate, requirements.getByteArray(PARAM_PUBLIC_KEY));
+ if (!publicKeyMatches) {
+ debugVerboseLog(
+ "Provided public key does not match leaf certificate public key.");
+ return false;
+ }
+ break;
+
+ case TYPE_CHALLENGE:
+ // Verify challenge matches provided challenge.
+ final boolean attestationChallengeMatches = checkAttestationChallenge(
+ attestationAttributes, requirements.getByteArray(PARAM_CHALLENGE));
+ if (!attestationChallengeMatches) {
+ debugVerboseLog(
+ "Provided challenge does not match leaf certificate challenge.");
+ return false;
+ }
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unsupported local binding type "
+ + localBindingTypeToString(localBindingType));
}
+ return true;
+ }
+
+ private boolean checkAttestationForPeerDeviceProfile(
+ @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes) {
// Checks for support of Keymaster 4.
if (attestationAttributes.getAttestationVersion() < 3) {
debugVerboseLog("Attestation version is not at least 3 (Keymaster 4).");
@@ -344,23 +391,20 @@ class AttestationVerificationPeerDeviceVerifier {
return false;
}
- // Verify leaf public key matches provided public key.
- if (localBindingType == TYPE_PUBLIC_KEY
- && !Arrays.equals(requirements.getByteArray(PARAM_PUBLIC_KEY),
- leafCertificate.getPublicKey().getEncoded())) {
- debugVerboseLog("Provided public key does not match leaf certificate public key.");
- return false;
- }
+ return true;
+ }
- // Verify challenge matches provided challenge.
- if (localBindingType == TYPE_CHALLENGE
- && !Arrays.equals(requirements.getByteArray(PARAM_CHALLENGE),
- attestationAttributes.getAttestationChallenge().toByteArray())) {
- debugVerboseLog("Provided challenge does not match leaf certificate challenge.");
- return false;
- }
+ private boolean checkPublicKey(
+ @NonNull Certificate certificate, @NonNull byte[] expectedPublicKey) {
+ final byte[] publicKey = certificate.getPublicKey().getEncoded();
+ return Arrays.equals(publicKey, expectedPublicKey);
+ }
- return true;
+ private boolean checkAttestationChallenge(
+ @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes,
+ @NonNull byte[] expectedChallenge) {
+ final byte[] challenge = attestationAttributes.getAttestationChallenge().toByteArray();
+ return Arrays.equals(challenge, expectedChallenge);
}
/**
@@ -507,4 +551,16 @@ class AttestationVerificationPeerDeviceVerifier {
R.string.vendor_required_attestation_revocation_list_url);
}
}
+
+ private static void debugVerboseLog(String str, Throwable t) {
+ if (DEBUG) {
+ Slog.v(TAG, str, t);
+ }
+ }
+
+ private static void debugVerboseLog(String str) {
+ if (DEBUG) {
+ Slog.v(TAG, str);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
index 94ea463e8bf7..d9f504e5f270 100644
--- a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
@@ -134,6 +134,10 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
newBoundServiceInfo = null;
}
+ // if the current connection is not connected, always force a rebind, helping with earlier
+ // recovery when something goes wrong with a connection.
+ forceRebind |= !mServiceConnection.isConnected();
+
if (forceRebind || !Objects.equals(mServiceConnection.getBoundServiceInfo(),
newBoundServiceInfo)) {
Log.i(TAG, "[" + mTag + "] chose new implementation " + newBoundServiceInfo);
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index e3dcfd0c89c0..881bdbd3bc6a 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -65,7 +65,6 @@ import com.android.internal.app.AssistUtils;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -226,12 +225,18 @@ public class SliceManagerService extends ISliceManager.Stub {
}
@Override
- public int checkSlicePermission(Uri uri, String callingPkg, String pkg, int pid, int uid,
+ public int checkSlicePermission(Uri uri, String callingPkg, int pid, int uid,
String[] autoGrantPermissions) {
+ return checkSlicePermissionInternal(uri, callingPkg, null /* pkg */, pid, uid,
+ autoGrantPermissions);
+ }
+
+ private int checkSlicePermissionInternal(Uri uri, String callingPkg, String pkg, int pid,
+ int uid, String[] autoGrantPermissions) {
int userId = UserHandle.getUserId(uid);
if (pkg == null) {
for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
- if (checkSlicePermission(uri, callingPkg, p, pid, uid, autoGrantPermissions)
+ if (checkSlicePermissionInternal(uri, callingPkg, p, pid, uid, autoGrantPermissions)
== PERMISSION_GRANTED) {
return PERMISSION_GRANTED;
}
@@ -395,7 +400,8 @@ public class SliceManagerService extends ISliceManager.Stub {
}
protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
- return checkSlicePermission(uri, null, pkg, pid, uid, null);
+ return checkSlicePermissionInternal(uri, null /* callingPkg */, pkg, pid, uid,
+ null /* autoGrantPermissions */);
}
private String getProviderPkg(Uri uri, int user) {
@@ -404,7 +410,7 @@ public class SliceManagerService extends ISliceManager.Stub {
String providerName = getUriWithoutUserId(uri).getAuthority();
ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
providerName, 0, getUserIdFromUri(uri, user));
- return provider.packageName;
+ return provider == null ? null : provider.packageName;
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -629,7 +635,7 @@ public class SliceManagerService extends ISliceManager.Stub {
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority)
.build(), 0);
- return mPermissions.getAllPackagesGranted(pkg);
+ return pkg == null ? new String[0] : mPermissions.getAllPackagesGranted(pkg);
}
/**
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index 5db4a7b4a6f6..d5b73b7fe990 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -28,6 +28,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.permission.PermissionManager;
import android.speech.IRecognitionListener;
@@ -103,6 +104,12 @@ final class SpeechRecognitionManagerServiceImpl extends
serviceComponent = getOnDeviceComponentNameLocked();
}
+ if (!onDevice && Process.isIsolated(Binder.getCallingUid())) {
+ Slog.w(TAG, "Isolated process can only start on device speech recognizer.");
+ tryRespondWithError(callback, SpeechRecognizer.ERROR_CLIENT);
+ return;
+ }
+
if (serviceComponent == null) {
if (mMaster.debug) {
Slog.i(TAG, "Service component is undefined, responding with error.");
diff --git a/services/core/java/com/android/server/testharness/OWNERS b/services/core/java/com/android/server/testharness/OWNERS
new file mode 100644
index 000000000000..ffbbeb9312b9
--- /dev/null
+++ b/services/core/java/com/android/server/testharness/OWNERS
@@ -0,0 +1 @@
+williamhester@google.com
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 8b2b8b1cfbac..b6a413524c5c 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -69,8 +69,8 @@ import java.util.Set;
* automatic updates, etc.) are all disabled by default but may be re-enabled by the user.
*/
public class TestHarnessModeService extends SystemService {
+ public static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
private static final String TAG = TestHarnessModeService.class.getSimpleName();
- private static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
private PersistentDataBlockManagerInternal mPersistentDataBlockManagerInternal;
@@ -168,9 +168,9 @@ public class TestHarnessModeService extends SystemService {
Slog.d(TAG, "Restarted adbd");
}
- // Disable the TTL for ADB keys before enabling ADB
+ // Disable the TTL for ADB keys before ADB is enabled as a part of AdbService's
+ // initialization.
Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
- Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 0);
Settings.Global.putInt(
diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
index f00f856c2910..683eaeb961b0 100644
--- a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
@@ -17,8 +17,13 @@
package com.android.server.timedetector;
import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+import static java.util.stream.Collectors.joining;
+
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.time.Capabilities.CapabilityState;
import android.app.time.TimeCapabilities;
@@ -26,21 +31,108 @@ import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.os.UserHandle;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
+import java.time.Instant;
+import java.util.Arrays;
import java.util.Objects;
/**
- * Holds configuration values that affect time behaviour.
+ * Holds configuration values that affect user-facing time behavior and some associated logic.
+ * Some configuration is global, some is user scoped, but this class deliberately doesn't make a
+ * distinction for simplicity.
*/
public final class ConfigurationInternal {
+ private final boolean mAutoDetectionSupported;
+ private final int mSystemClockUpdateThresholdMillis;
+ private final Instant mAutoTimeLowerBound;
+ private final @Origin int[] mOriginPriorities;
+ private final boolean mDeviceHasY2038Issue;
+ private final boolean mAutoDetectionEnabledSetting;
private final @UserIdInt int mUserId;
private final boolean mUserConfigAllowed;
- private final boolean mAutoDetectionEnabled;
private ConfigurationInternal(Builder builder) {
+ mAutoDetectionSupported = builder.mAutoDetectionSupported;
+ mSystemClockUpdateThresholdMillis = builder.mSystemClockUpdateThresholdMillis;
+ mAutoTimeLowerBound = Objects.requireNonNull(builder.mAutoTimeLowerBound);
+ mOriginPriorities = Objects.requireNonNull(builder.mOriginPriorities);
+ mDeviceHasY2038Issue = builder.mDeviceHasY2038Issue;
+ mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting;
+
mUserId = builder.mUserId;
mUserConfigAllowed = builder.mUserConfigAllowed;
- mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+ }
+
+ /** Returns true if the device supports any form of auto time detection. */
+ public boolean isAutoDetectionSupported() {
+ return mAutoDetectionSupported;
+ }
+
+ /**
+ * Returns the absolute threshold below which the system clock need not be updated. i.e. if
+ * setting the system clock would adjust it by less than this (either backwards or forwards)
+ * then it need not be set.
+ */
+ public int getSystemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ /**
+ * Returns the lower bound for valid automatic times. It is guaranteed to be in the past,
+ * i.e. it is unrelated to the current system clock time.
+ * It holds no other meaning; it could be related to when the device system image was built,
+ * or could be updated by a mainline module.
+ */
+ @NonNull
+ public Instant getAutoTimeLowerBound() {
+ return mAutoTimeLowerBound;
+ }
+
+ /**
+ * Returns the order to look at time suggestions when automatically detecting time.
+ * See {@code #ORIGIN_} constants
+ */
+ public @Origin int[] getAutoOriginPriorities() {
+ return mOriginPriorities;
+ }
+
+ /**
+ * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
+ * defines time_t as a 32-bit signed integer for 32-bit processes).
+ */
+ public boolean getDeviceHasY2038Issue() {
+ return mDeviceHasY2038Issue;
+ }
+
+ /** Returns the value of the auto time detection enabled setting. */
+ public boolean getAutoDetectionEnabledSetting() {
+ return mAutoDetectionEnabledSetting;
+ }
+
+ /**
+ * Returns true if auto time detection behavior is actually enabled, which can be distinct
+ * from the raw setting value.
+ */
+ public boolean getAutoDetectionEnabledBehavior() {
+ return isAutoDetectionSupported() && mAutoDetectionEnabledSetting;
+ }
+
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /** Returns the handle of the user this configuration is associated with. */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return UserHandle.of(mUserId);
+ }
+
+ /** Returns true if the user allowed to modify time zone configuration. */
+ public boolean isUserConfigAllowed() {
+ return mUserConfigAllowed;
}
/** Returns a {@link TimeCapabilitiesAndConfig} objects based on configuration values. */
@@ -48,73 +140,197 @@ public final class ConfigurationInternal {
return new TimeCapabilitiesAndConfig(timeCapabilities(), timeConfiguration());
}
+ private TimeCapabilities timeCapabilities() {
+ UserHandle userHandle = UserHandle.of(mUserId);
+ TimeCapabilities.Builder builder = new TimeCapabilities.Builder(userHandle);
+
+ boolean allowConfigDateTime = isUserConfigAllowed();
+
+ boolean deviceHasAutoTimeDetection = isAutoDetectionSupported();
+ final @CapabilityState int configureAutoDetectionEnabledCapability;
+ if (!deviceHasAutoTimeDetection) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+ } else if (!allowConfigDateTime) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+ } else {
+ configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
+
+ // The ability to make manual time suggestions can also be restricted by policy. With the
+ // current logic above, this could lead to a situation where a device hardware does not
+ // support auto detection, the device has been forced into "auto" mode by an admin and the
+ // user is unable to disable auto detection.
+ final @CapabilityState int suggestManualTimeZoneCapability;
+ if (!allowConfigDateTime) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
+ } else if (getAutoDetectionEnabledBehavior()) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
+ } else {
+ suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setSuggestManualTimeCapability(suggestManualTimeZoneCapability);
+
+ return builder.build();
+ }
+
+ /** Returns a {@link TimeConfiguration} from the configuration values. */
private TimeConfiguration timeConfiguration() {
return new TimeConfiguration.Builder()
- .setAutoDetectionEnabled(mAutoDetectionEnabled)
+ .setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
.build();
}
- private TimeCapabilities timeCapabilities() {
- @CapabilityState int configureAutoTimeDetectionEnabledCapability =
- mUserConfigAllowed
- ? CAPABILITY_POSSESSED
- : CAPABILITY_NOT_ALLOWED;
-
- @CapabilityState int suggestTimeManuallyCapability =
- mUserConfigAllowed
- ? CAPABILITY_POSSESSED
- : CAPABILITY_NOT_ALLOWED;
-
- return new TimeCapabilities.Builder(UserHandle.of(mUserId))
- .setConfigureAutoTimeDetectionEnabledCapability(
- configureAutoTimeDetectionEnabledCapability)
- .setSuggestTimeManuallyCapability(suggestTimeManuallyCapability)
- .build();
+ /**
+ * Merges the configuration values from this with any properties set in {@code
+ * newConfiguration}. The new configuration has precedence. Used to apply user updates to
+ * internal configuration.
+ */
+ public ConfigurationInternal merge(TimeConfiguration newConfiguration) {
+ Builder builder = new Builder(this);
+ if (newConfiguration.hasIsAutoDetectionEnabled()) {
+ builder.setAutoDetectionEnabledSetting(newConfiguration.isAutoDetectionEnabled());
+ }
+ return builder.build();
}
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ConfigurationInternal)) {
+ return false;
+ }
ConfigurationInternal that = (ConfigurationInternal) o;
- return mUserId == that.mUserId
- && mUserConfigAllowed == that.mUserConfigAllowed
- && mAutoDetectionEnabled == that.mAutoDetectionEnabled;
+ return mAutoDetectionSupported == that.mAutoDetectionSupported
+ && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
+ && mUserId == that.mUserId && mUserConfigAllowed == that.mUserConfigAllowed
+ && mSystemClockUpdateThresholdMillis == that.mSystemClockUpdateThresholdMillis
+ && mAutoTimeLowerBound.equals(that.mAutoTimeLowerBound)
+ && mDeviceHasY2038Issue == that.mDeviceHasY2038Issue
+ && Arrays.equals(mOriginPriorities, that.mOriginPriorities);
}
@Override
public int hashCode() {
- return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionEnabled);
+ int result = Objects.hash(mAutoDetectionSupported, mAutoDetectionEnabledSetting, mUserId,
+ mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoTimeLowerBound,
+ mDeviceHasY2038Issue);
+ result = 31 * result + Arrays.hashCode(mOriginPriorities);
+ return result;
}
@Override
public String toString() {
+ String originPrioritiesString =
+ Arrays.stream(mOriginPriorities)
+ .mapToObj(TimeDetectorStrategy::originToString)
+ .collect(joining(",", "[", "]"));
return "ConfigurationInternal{"
- + "mUserId=" + mUserId
+ + "mAutoDetectionSupported=" + mAutoDetectionSupported
+ + ", mSystemClockUpdateThresholdMillis=" + mSystemClockUpdateThresholdMillis
+ + ", mAutoTimeLowerBound=" + mAutoTimeLowerBound
+ + "(" + mAutoTimeLowerBound.toEpochMilli() + ")"
+ + ", mOriginPriorities=" + originPrioritiesString
+ + ", mDeviceHasY2038Issue=" + mDeviceHasY2038Issue
+ + ", mAutoDetectionEnabled=" + mAutoDetectionEnabledSetting
+ + ", mUserId=" + mUserId
+ ", mUserConfigAllowed=" + mUserConfigAllowed
- + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled
+ '}';
}
static final class Builder {
+ private boolean mAutoDetectionSupported;
+ private int mSystemClockUpdateThresholdMillis;
+ @NonNull private Instant mAutoTimeLowerBound;
+ @NonNull private @Origin int[] mOriginPriorities;
+ private boolean mDeviceHasY2038Issue;
+ private boolean mAutoDetectionEnabledSetting;
+
private final @UserIdInt int mUserId;
private boolean mUserConfigAllowed;
- private boolean mAutoDetectionEnabled;
Builder(@UserIdInt int userId) {
mUserId = userId;
}
+ /**
+ * Creates a new Builder by copying values from an existing instance.
+ */
+ Builder(ConfigurationInternal toCopy) {
+ this.mUserId = toCopy.mUserId;
+ this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
+ this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
+ this.mSystemClockUpdateThresholdMillis = toCopy.mSystemClockUpdateThresholdMillis;
+ this.mAutoTimeLowerBound = toCopy.mAutoTimeLowerBound;
+ this.mOriginPriorities = toCopy.mOriginPriorities;
+ this.mDeviceHasY2038Issue = toCopy.mDeviceHasY2038Issue;
+ this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
+ }
+
+ /**
+ * Sets whether the user is allowed to configure time settings on this device.
+ */
Builder setUserConfigAllowed(boolean userConfigAllowed) {
mUserConfigAllowed = userConfigAllowed;
return this;
}
- Builder setAutoDetectionEnabled(boolean autoDetectionEnabled) {
- mAutoDetectionEnabled = autoDetectionEnabled;
+ /**
+ * Sets whether automatic time detection is supported on this device.
+ */
+ public Builder setAutoDetectionSupported(boolean supported) {
+ mAutoDetectionSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the absolute threshold below which the system clock need not be updated. i.e. if
+ * setting the system clock would adjust it by less than this (either backwards or forwards)
+ * then it need not be set.
+ */
+ public Builder setSystemClockUpdateThresholdMillis(int systemClockUpdateThresholdMillis) {
+ mSystemClockUpdateThresholdMillis = systemClockUpdateThresholdMillis;
+ return this;
+ }
+
+ /**
+ * Sets the lower bound for valid automatic times.
+ */
+ public Builder setAutoTimeLowerBound(@NonNull Instant autoTimeLowerBound) {
+ mAutoTimeLowerBound = Objects.requireNonNull(autoTimeLowerBound);
+ return this;
+ }
+
+ /**
+ * Sets the order to look at time suggestions when automatically detecting time.
+ * See {@code #ORIGIN_} constants
+ */
+ public Builder setOriginPriorities(@NonNull @Origin int... originPriorities) {
+ mOriginPriorities = Objects.requireNonNull(originPriorities);
+ return this;
+ }
+
+ /**
+ * Sets the value of the automatic time detection enabled setting for this device.
+ */
+ Builder setAutoDetectionEnabledSetting(boolean autoDetectionEnabledSetting) {
+ mAutoDetectionEnabledSetting = autoDetectionEnabledSetting;
+ return this;
+ }
+
+ /**
+ * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
+ * defines time_t as a 32-bit signed integer for 32-bit processes).
+ */
+ Builder setDeviceHasY2038Issue(boolean deviceHasY2038Issue) {
+ mDeviceHasY2038Issue = deviceHasY2038Issue;
return this;
}
+ /** Returns a new {@link ConfigurationInternal}. */
+ @NonNull
ConfigurationInternal build() {
return new ConfigurationInternal(this);
}
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 7649958fe6c9..3e02b463284d 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -17,23 +17,15 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
-import android.annotation.UserIdInt;
import android.app.AlarmManager;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.server.timezonedetector.ConfigurationChangeListener;
-import java.time.Instant;
import java.util.Objects;
/**
@@ -43,22 +35,13 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
private static final String LOG_TAG = TimeDetectorService.TAG;
- @NonNull private final Context mContext;
@NonNull private final Handler mHandler;
@NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
- @NonNull private final ContentResolver mContentResolver;
@NonNull private final PowerManager.WakeLock mWakeLock;
@NonNull private final AlarmManager mAlarmManager;
- @NonNull private final UserManager mUserManager;
-
- // @NonNull after setConfigChangeListener() is called.
- @GuardedBy("this")
- private ConfigurationChangeListener mConfigChangeListener;
EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull ServiceConfigAccessor serviceConfigAccessor) {
- mContext = Objects.requireNonNull(context);
- mContentResolver = Objects.requireNonNull(context.getContentResolver());
mHandler = Objects.requireNonNull(handler);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
@@ -67,73 +50,19 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG));
mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
-
- mUserManager = Objects.requireNonNull(context.getSystemService(UserManager.class));
-
- // Wire up the config change listeners. All invocations are performed on the mHandler
- // thread.
-
- ContentResolver contentResolver = context.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
- new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- handleAutoTimeDetectionChangedOnHandlerThread();
- }
- });
- mServiceConfigAccessor.addListener(
- () -> mHandler.post(
- EnvironmentImpl.this::handleAutoTimeDetectionChangedOnHandlerThread));
- }
-
- /** Internal method for handling the auto time setting being changed. */
- private void handleAutoTimeDetectionChangedOnHandlerThread() {
- synchronized (this) {
- if (mConfigChangeListener == null) {
- Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
- }
- mConfigChangeListener.onChange();
- }
}
@Override
- public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
- synchronized (this) {
- mConfigChangeListener = Objects.requireNonNull(listener);
- }
+ public void setConfigurationInternalChangeListener(
+ @NonNull ConfigurationChangeListener listener) {
+ ConfigurationChangeListener configurationChangeListener =
+ () -> mHandler.post(listener::onChange);
+ mServiceConfigAccessor.addConfigurationInternalChangeListener(configurationChangeListener);
}
@Override
- public int systemClockUpdateThresholdMillis() {
- return mServiceConfigAccessor.systemClockUpdateThresholdMillis();
- }
-
- @Override
- public boolean isAutoTimeDetectionEnabled() {
- try {
- return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
- } catch (Settings.SettingNotFoundException snfe) {
- return true;
- }
- }
-
- @Override
- public Instant autoTimeLowerBound() {
- return mServiceConfigAccessor.autoTimeLowerBound();
- }
-
- @Override
- public int[] autoOriginPriorities() {
- return mServiceConfigAccessor.getOriginPriorities();
- }
-
- @Override
- public ConfigurationInternal configurationInternal(@UserIdInt int userId) {
- return new ConfigurationInternal.Builder(userId)
- .setUserConfigAllowed(isUserConfigAllowed(userId))
- .setAutoDetectionEnabled(isAutoTimeDetectionEnabled())
- .build();
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mServiceConfigAccessor.getCurrentUserConfigurationInternal();
}
@Override
@@ -171,9 +100,4 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
}
}
-
- private boolean isUserConfigAllowed(@UserIdInt int userId) {
- UserHandle userHandle = UserHandle.of(userId);
- return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
- }
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
index 2015dc929a59..53893252c94b 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -71,7 +71,7 @@ public class NetworkTimeUpdateService extends Binder {
private static final int EVENT_NETWORK_CHANGED = 3;
private static final String ACTION_POLL =
- "com.android.server.NetworkTimeUpdateService.action.POLL";
+ "com.android.server.timedetector.NetworkTimeUpdateService.action.POLL";
private static final int POLL_REQUEST = 0;
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java
index d7504ceb9d4d..18dda55c4270 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.timedetector;
import android.annotation.NonNull;
import android.os.ShellCommand;
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
index 5f1400097a3a..25a74ceeb56d 100644
--- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
@@ -15,214 +15,54 @@
*/
package com.android.server.timedetector;
-import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE;
-import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
-
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
-import android.os.SystemProperties;
+import android.annotation.UserIdInt;
+import android.app.time.TimeConfiguration;
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.server.timezonedetector.ConfigurationChangeListener;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Supplier;
-
/**
- * A singleton that provides access to service configuration for time detection. This hides how
- * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
- * provides a rudimentary mechanism to signal when values have changed.
+ * An interface that provides access to service configuration for time detection. This hides
+ * how configuration is split between static, compile-time config, dynamic server-pushed flags and
+ * user settings. It provides listeners to signal when values that affect different components have
+ * changed.
*/
-final class ServiceConfigAccessor {
-
- private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
-
- /**
- * By default telephony and network only suggestions are accepted and telephony takes
- * precedence over network.
- */
- private static final @Origin int[]
- DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+public interface ServiceConfigAccessor {
/**
- * Time in the past. If an automatic time suggestion is before this point, it is sure to be
- * incorrect.
+ * Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed.
+ * The listener is invoked on the main thread.
*/
- private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
- Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
-
- /** Device config keys that affect the {@link TimeDetectorService}. */
- private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of(
- KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
- KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE
- );
-
- private static final Object SLOCK = new Object();
-
- /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
- @GuardedBy("SLOCK")
- @Nullable
- private static ServiceConfigAccessor sInstance;
-
- @NonNull private final Context mContext;
- @NonNull private final ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier;
- @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier;
- @NonNull private final ServerFlags mServerFlags;
+ void addConfigurationInternalChangeListener(@NonNull ConfigurationChangeListener listener);
/**
- * If a newly calculated system clock time and the current system clock time differs by this or
- * more the system clock will actually be updated. Used to prevent the system clock being set
- * for only minor differences.
+ * Removes a listener previously added via {@link
+ * #addConfigurationInternalChangeListener(ConfigurationChangeListener)}.
*/
- private final int mSystemClockUpdateThresholdMillis;
-
- private ServiceConfigAccessor(@NonNull Context context) {
- mContext = Objects.requireNonNull(context);
- mServerFlags = ServerFlags.getInstance(mContext);
- mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context);
- mServerFlagsOriginPrioritiesSupplier =
- new ServerFlagsOriginPrioritiesSupplier(mServerFlags);
- mSystemClockUpdateThresholdMillis =
- SystemProperties.getInt("ro.sys.time_detector_update_diff",
- SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
- }
-
- /** Returns the singleton instance. */
- static ServiceConfigAccessor getInstance(Context context) {
- synchronized (SLOCK) {
- if (sInstance == null) {
- sInstance = new ServiceConfigAccessor(context);
- }
- return sInstance;
- }
- }
+ void removeConfigurationInternalChangeListener(@NonNull ConfigurationChangeListener listener);
/**
- * Adds a listener that will be called when server flags related to this class change. The
- * callbacks are delivered on the main looper thread.
- *
- * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
- * method.
+ * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a
+ * snapshot so callers must use {@link
+ * #addConfigurationInternalChangeListener(ConfigurationChangeListener)} to be notified when it
+ * changes.
*/
- void addListener(@NonNull ConfigurationChangeListener listener) {
- mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
- }
-
@NonNull
- @Origin int[] getOriginPriorities() {
- int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get();
- if (serverFlagsValue != null) {
- return serverFlagsValue;
- }
-
- int[] configValue = mConfigOriginPrioritiesSupplier.get();
- if (configValue != null) {
- return configValue;
- }
- return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
- }
-
- int systemClockUpdateThresholdMillis() {
- return mSystemClockUpdateThresholdMillis;
- }
-
- @NonNull
- Instant autoTimeLowerBound() {
- return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE)
- .orElse(TIME_LOWER_BOUND_DEFAULT);
- }
+ ConfigurationInternal getCurrentUserConfigurationInternal();
/**
- * A base supplier of an array of time origin integers in priority order.
- * It handles memoization of the result to avoid repeated string parsing when nothing has
- * changed.
+ * Updates the configuration properties that control a device's time behavior.
+ *
+ * <p>This method returns {@code true} if the configuration was changed,
+ * {@code false} otherwise.
*/
- private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> {
- @GuardedBy("this") @Nullable private String[] mLastPriorityStrings;
- @GuardedBy("this") @Nullable private int[] mLastPriorityInts;
-
- /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */
- @Override
- @Nullable
- public @Origin int[] get() {
- String[] priorityStrings = lookupPriorityStrings();
- synchronized (this) {
- if (Arrays.equals(mLastPriorityStrings, priorityStrings)) {
- return mLastPriorityInts;
- }
-
- int[] priorityInts = null;
- if (priorityStrings != null && priorityStrings.length > 0) {
- priorityInts = new int[priorityStrings.length];
- try {
- for (int i = 0; i < priorityInts.length; i++) {
- String priorityString = priorityStrings[i];
- Preconditions.checkArgument(priorityString != null);
-
- priorityString = priorityString.trim();
- priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString);
- }
- } catch (IllegalArgumentException e) {
- // If any strings were bad and they were ignored then the semantics of the
- // whole list could change, so return null.
- priorityInts = null;
- }
- }
- mLastPriorityStrings = priorityStrings;
- mLastPriorityInts = priorityInts;
- return priorityInts;
- }
- }
-
- @Nullable
- protected abstract String[] lookupPriorityStrings();
- }
-
- /** Supplies origin priorities from config_autoTimeSourcesPriority. */
- private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier {
-
- @NonNull private final Context mContext;
-
- private ConfigOriginPrioritiesSupplier(Context context) {
- mContext = Objects.requireNonNull(context);
- }
-
- @Override
- @Nullable
- protected String[] lookupPriorityStrings() {
- return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
- }
- }
+ boolean updateConfiguration(
+ @UserIdInt int userId, @NonNull TimeConfiguration requestedConfiguration);
/**
- * Supplies origin priorities from device_config (server flags), see
- * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}.
+ * Returns a snapshot of the configuration that controls time zone detector behavior for the
+ * specified user.
*/
- private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier {
-
- @NonNull private final ServerFlags mServerFlags;
-
- private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) {
- mServerFlags = Objects.requireNonNull(serverFlags);
- }
-
- @Override
- @Nullable
- protected String[] lookupPriorityStrings() {
- Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray(
- KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE);
- return priorityStrings.orElse(null);
- }
- }
+ @NonNull
+ ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
}
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
new file mode 100644
index 000000000000..b161cc720458
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
@@ -0,0 +1,399 @@
+/*
+ * 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.
+ */
+package com.android.server.timedetector;
+
+import static android.content.Intent.ACTION_USER_SWITCHED;
+
+import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_EXTERNAL;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_GNSS;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.time.TimeCapabilities;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * A singleton implementation of {@link ServiceConfigAccessor}.
+ */
+final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
+
+ private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
+
+ /**
+ * By default telephony and network only suggestions are accepted and telephony takes
+ * precedence over network.
+ */
+ private static final @Origin int[]
+ DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+
+ /**
+ * Time in the past. If an automatic time suggestion is before this point, it is sure to be
+ * incorrect.
+ */
+ private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
+ Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
+
+ /** Device config keys that affect the {@link TimeDetectorService}. */
+ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of(
+ KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
+ KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE
+ );
+
+ private static final Object SLOCK = new Object();
+
+ /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
+ @GuardedBy("SLOCK")
+ @Nullable
+ private static ServiceConfigAccessor sInstance;
+
+ @NonNull private final Context mContext;
+ @NonNull private final ServerFlags mServerFlags;
+ @NonNull private final ContentResolver mCr;
+ @NonNull private final UserManager mUserManager;
+ @NonNull private final ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier;
+ @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier;
+
+ @GuardedBy("this")
+ @NonNull private final List<ConfigurationChangeListener> mConfigurationInternalListeners =
+ new ArrayList<>();
+
+ /**
+ * If a newly calculated system clock time and the current system clock time differs by this or
+ * more the system clock will actually be updated. Used to prevent the system clock being set
+ * for only minor differences.
+ */
+ private final int mSystemClockUpdateThresholdMillis;
+
+ private ServiceConfigAccessorImpl(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+ mCr = context.getContentResolver();
+ mUserManager = context.getSystemService(UserManager.class);
+ mServerFlags = ServerFlags.getInstance(mContext);
+ mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context);
+ mServerFlagsOriginPrioritiesSupplier =
+ new ServerFlagsOriginPrioritiesSupplier(mServerFlags);
+ mSystemClockUpdateThresholdMillis =
+ SystemProperties.getInt("ro.sys.time_detector_update_diff",
+ SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+
+ // Wire up the config change listeners for anything that could affect ConfigurationInternal.
+ // Use the main thread for event delivery, listeners can post to their chosen thread.
+
+ // Listen for the user changing / the user's location mode changing. Report on the main
+ // thread.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USER_SWITCHED);
+ mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleConfigurationInternalChangeOnMainThread();
+ }
+ }, filter, null, null /* main thread */);
+
+ // Add async callbacks for global settings being changed.
+ ContentResolver contentResolver = mContext.getContentResolver();
+ ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handleConfigurationInternalChangeOnMainThread();
+ }
+ };
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, contentObserver);
+
+ // Watch server flags.
+ mServerFlags.addListener(this::handleConfigurationInternalChangeOnMainThread,
+ SERVER_FLAGS_KEYS_TO_WATCH);
+ }
+
+ /** Returns the singleton instance. */
+ static ServiceConfigAccessor getInstance(Context context) {
+ synchronized (SLOCK) {
+ if (sInstance == null) {
+ sInstance = new ServiceConfigAccessorImpl(context);
+ }
+ return sInstance;
+ }
+ }
+
+ private synchronized void handleConfigurationInternalChangeOnMainThread() {
+ for (ConfigurationChangeListener changeListener : mConfigurationInternalListeners) {
+ changeListener.onChange();
+ }
+ }
+
+ @Override
+ public synchronized void addConfigurationInternalChangeListener(
+ @NonNull ConfigurationChangeListener listener) {
+ mConfigurationInternalListeners.add(Objects.requireNonNull(listener));
+ }
+
+ @Override
+ public synchronized void removeConfigurationInternalChangeListener(
+ @NonNull ConfigurationChangeListener listener) {
+ mConfigurationInternalListeners.remove(Objects.requireNonNull(listener));
+ }
+
+ @Override
+ @NonNull
+ public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
+ int currentUserId =
+ LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
+ return getConfigurationInternal(currentUserId);
+ }
+
+ @Override
+ public synchronized boolean updateConfiguration(@UserIdInt int userId,
+ @NonNull TimeConfiguration requestedConfiguration) {
+ Objects.requireNonNull(requestedConfiguration);
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig =
+ getCurrentUserConfigurationInternal().capabilitiesAndConfig();
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ TimeConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
+
+ final TimeConfiguration newConfiguration =
+ capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
+ if (newConfiguration == null) {
+ // The changes could not be made because the user's capabilities do not allow it.
+ return false;
+ }
+
+ // Store the configuration / notify as needed. This will cause the mEnvironment to invoke
+ // handleConfigChanged() asynchronously.
+ storeConfiguration(userId, newConfiguration);
+
+ return true;
+ }
+
+ /**
+ * Stores the configuration properties contained in {@code newConfiguration}.
+ * All checks about user capabilities must be done by the caller and
+ * {@link TimeConfiguration#isComplete()} must be {@code true}.
+ */
+ @GuardedBy("this")
+ private void storeConfiguration(
+ @UserIdInt int userId, @NonNull TimeConfiguration configuration) {
+ Objects.requireNonNull(configuration);
+
+ // Avoid writing the auto detection enabled setting for devices that do not support auto
+ // time detection: if we wrote it down then we'd set the value explicitly, which would
+ // prevent detecting "default" later. That might influence what happens on later releases
+ // that support new types of auto detection on the same hardware.
+ if (isAutoDetectionSupported()) {
+ final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+ setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
+ }
+ }
+
+ @Override
+ @NonNull
+ public synchronized ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ return new ConfigurationInternal.Builder(userId)
+ .setUserConfigAllowed(isUserConfigAllowed(userId))
+ .setAutoDetectionSupported(isAutoDetectionSupported())
+ .setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting())
+ .setSystemClockUpdateThresholdMillis(getSystemClockUpdateThresholdMillis())
+ .setAutoTimeLowerBound(getAutoTimeLowerBound())
+ .setOriginPriorities(getOriginPriorities())
+ .setDeviceHasY2038Issue(getDeviceHasY2038Issue())
+ .build();
+ }
+
+ private void setAutoDetectionEnabledIfRequired(boolean enabled) {
+ // This check is racey, but the whole settings update process is racey. This check prevents
+ // a ConfigurationChangeListener callback triggering due to ContentObserver's still
+ // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary
+ // for stable behavior during tests.
+ if (getAutoDetectionEnabledSetting() != enabled) {
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME, enabled ? 1 : 0);
+ }
+ }
+
+ private boolean isUserConfigAllowed(@UserIdInt int userId) {
+ UserHandle userHandle = UserHandle.of(userId);
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+ }
+
+ private boolean getAutoDetectionEnabledSetting() {
+ return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 1 /* default */) > 0;
+ }
+
+ /** Returns {@code true} if any form of automatic time detection is supported. */
+ private boolean isAutoDetectionSupported() {
+ @Origin int[] originsSupported = getOriginPriorities();
+ for (@Origin int originSupported : originsSupported) {
+ if (originSupported == ORIGIN_NETWORK
+ || originSupported == ORIGIN_EXTERNAL
+ || originSupported == ORIGIN_GNSS) {
+ return true;
+ } else if (originSupported == ORIGIN_TELEPHONY) {
+ boolean deviceHasTelephony = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ if (deviceHasTelephony) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int getSystemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ @NonNull
+ private Instant getAutoTimeLowerBound() {
+ return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE)
+ .orElse(TIME_LOWER_BOUND_DEFAULT);
+ }
+
+ @NonNull
+ private @Origin int[] getOriginPriorities() {
+ @Origin int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get();
+ if (serverFlagsValue != null) {
+ return serverFlagsValue;
+ }
+
+ @Origin int[] configValue = mConfigOriginPrioritiesSupplier.get();
+ if (configValue != null) {
+ return configValue;
+ }
+ return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
+ }
+
+ private boolean getDeviceHasY2038Issue() {
+ return Build.SUPPORTED_32_BIT_ABIS.length > 0;
+ }
+
+ /**
+ * A base supplier of an array of time origin integers in priority order.
+ * It handles memoization of the result to avoid repeated string parsing when nothing has
+ * changed.
+ */
+ private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> {
+ @GuardedBy("this") @Nullable private String[] mLastPriorityStrings;
+ @GuardedBy("this") @Nullable private int[] mLastPriorityInts;
+
+ /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */
+ @Override
+ @Nullable
+ public @Origin int[] get() {
+ String[] priorityStrings = lookupPriorityStrings();
+ synchronized (this) {
+ if (Arrays.equals(mLastPriorityStrings, priorityStrings)) {
+ return mLastPriorityInts;
+ }
+
+ int[] priorityInts = null;
+ if (priorityStrings != null && priorityStrings.length > 0) {
+ priorityInts = new int[priorityStrings.length];
+ try {
+ for (int i = 0; i < priorityInts.length; i++) {
+ String priorityString = priorityStrings[i];
+ Preconditions.checkArgument(priorityString != null);
+
+ priorityString = priorityString.trim();
+ priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString);
+ }
+ } catch (IllegalArgumentException e) {
+ // If any strings were bad and they were ignored then the semantics of the
+ // whole list could change, so return null.
+ priorityInts = null;
+ }
+ }
+ mLastPriorityStrings = priorityStrings;
+ mLastPriorityInts = priorityInts;
+ return priorityInts;
+ }
+ }
+
+ @Nullable
+ protected abstract String[] lookupPriorityStrings();
+ }
+
+ /** Supplies origin priorities from config_autoTimeSourcesPriority. */
+ private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier {
+
+ @NonNull private final Context mContext;
+
+ private ConfigOriginPrioritiesSupplier(Context context) {
+ mContext = Objects.requireNonNull(context);
+ }
+
+ @Override
+ @Nullable
+ protected String[] lookupPriorityStrings() {
+ return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
+ }
+ }
+
+ /**
+ * Supplies origin priorities from device_config (server flags), see
+ * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}.
+ */
+ private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier {
+
+ @NonNull private final ServerFlags mServerFlags;
+
+ private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) {
+ mServerFlags = Objects.requireNonNull(serverFlags);
+ }
+
+ @Override
+ @Nullable
+ protected String[] lookupPriorityStrings() {
+ Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray(
+ KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE);
+ return priorityStrings.orElse(null);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 0f14af4b296b..105cd78f2a07 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,7 +19,9 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.ITimeDetectorListener;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
@@ -30,10 +32,15 @@ import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
+import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
@@ -52,7 +59,8 @@ import java.util.Objects;
* and making calls async, leaving the (consequently more testable) {@link TimeDetectorStrategy}
* implementation to deal with the logic around time detection.
*/
-public final class TimeDetectorService extends ITimeDetectorService.Stub {
+public final class TimeDetectorService extends ITimeDetectorService.Stub
+ implements IBinder.DeathRecipient {
static final String TAG = "time_detector";
public static class Lifecycle extends SystemService {
@@ -67,12 +75,12 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
Handler handler = FgThread.getHandler();
ServiceConfigAccessor serviceConfigAccessor =
- ServiceConfigAccessor.getInstance(context);
+ ServiceConfigAccessorImpl.getInstance(context);
TimeDetectorStrategy timeDetectorStrategy =
TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
- TimeDetectorService service =
- new TimeDetectorService(context, handler, timeDetectorStrategy);
+ TimeDetectorService service = new TimeDetectorService(
+ context, handler, serviceConfigAccessor, timeDetectorStrategy);
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
@@ -82,23 +90,41 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@NonNull private final Handler mHandler;
@NonNull private final Context mContext;
- @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
@NonNull private final CallerIdentityInjector mCallerIdentityInjector;
+ @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
+ @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+
+ /**
+ * Holds the listeners. The key is the {@link IBinder} associated with the listener, the value
+ * is the listener itself.
+ */
+ @GuardedBy("mListeners")
+ @NonNull
+ private final ArrayMap<IBinder, ITimeDetectorListener> mListeners = new ArrayMap<>();
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
- this(context, handler, timeDetectorStrategy, CallerIdentityInjector.REAL);
+ this(context, handler, serviceConfigAccessor, timeDetectorStrategy,
+ CallerIdentityInjector.REAL);
}
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy,
@NonNull CallerIdentityInjector callerIdentityInjector) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
+
+ // Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
+ // the configuration changes for any reason.
+ mServiceConfigAccessor.addConfigurationInternalChangeListener(
+ () -> mHandler.post(this::handleConfigurationInternalChangedOnHandlerThread));
}
@Override
@@ -108,13 +134,13 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
return getTimeCapabilitiesAndConfig(userId);
}
- private TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
+ TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
enforceManageTimeDetectorPermission();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
ConfigurationInternal configurationInternal =
- mTimeDetectorStrategy.getConfigurationInternal(userId);
+ mServiceConfigAccessor.getConfigurationInternal(userId);
return configurationInternal.capabilitiesAndConfig();
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
@@ -122,10 +148,117 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
@Override
- public boolean updateConfiguration(@NonNull TimeConfiguration timeConfiguration) {
+ public boolean updateConfiguration(@NonNull TimeConfiguration configuration) {
+ int callingUserId = mCallerIdentityInjector.getCallingUserId();
+ return updateConfiguration(callingUserId, configuration);
+ }
+
+ boolean updateConfiguration(@UserIdInt int userId, @NonNull TimeConfiguration configuration) {
+ // Resolve constants like USER_CURRENT to the true user ID as needed.
+ int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, false, "updateConfiguration", null);
+
+ enforceManageTimeDetectorPermission();
+
+ Objects.requireNonNull(configuration);
+
+ final long token = mCallerIdentityInjector.clearCallingIdentity();
+ try {
+ return mServiceConfigAccessor.updateConfiguration(resolvedUserId, configuration);
+ } finally {
+ mCallerIdentityInjector.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void addListener(@NonNull ITimeDetectorListener listener) {
enforceManageTimeDetectorPermission();
- // TODO(b/172891783) Add actual logic
- return false;
+ Objects.requireNonNull(listener);
+
+ synchronized (mListeners) {
+ IBinder listenerBinder = listener.asBinder();
+ if (mListeners.containsKey(listenerBinder)) {
+ return;
+ }
+ try {
+ // Ensure the reference to the listener will be removed if the client process dies.
+ listenerBinder.linkToDeath(this, 0 /* flags */);
+
+ // Only add the listener if we can linkToDeath().
+ mListeners.put(listenerBinder, listener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
+ }
+ }
+ }
+
+ @Override
+ public void removeListener(@NonNull ITimeDetectorListener listener) {
+ enforceManageTimeDetectorPermission();
+ Objects.requireNonNull(listener);
+
+ synchronized (mListeners) {
+ IBinder listenerBinder = listener.asBinder();
+ boolean removedListener = false;
+ if (mListeners.remove(listenerBinder) != null) {
+ // Stop listening for the client process to die.
+ listenerBinder.unlinkToDeath(this, 0 /* flags */);
+ removedListener = true;
+ }
+ if (!removedListener) {
+ Slog.w(TAG, "Client asked to remove listener=" + listener
+ + ", but no listeners were removed."
+ + " mListeners=" + mListeners);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Should not be used as binderDied(IBinder who) is overridden.
+ Slog.wtf(TAG, "binderDied() called unexpectedly.");
+ }
+
+ /**
+ * Called when one of the ITimeDetectorListener processes dies before calling
+ * {@link #removeListener(ITimeDetectorListener)}.
+ */
+ @Override
+ public void binderDied(IBinder who) {
+ synchronized (mListeners) {
+ boolean removedListener = false;
+ final int listenerCount = mListeners.size();
+ for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
+ IBinder listenerBinder = mListeners.keyAt(listenerIndex);
+ if (listenerBinder.equals(who)) {
+ mListeners.removeAt(listenerIndex);
+ removedListener = true;
+ break;
+ }
+ }
+ if (!removedListener) {
+ Slog.w(TAG, "Notified of binder death for who=" + who
+ + ", but did not remove any listeners."
+ + " mListeners=" + mListeners);
+ }
+ }
+ }
+
+ void handleConfigurationInternalChangedOnHandlerThread() {
+ // Configuration has changed, but each user may have a different view of the configuration.
+ // It's possible that this will cause unnecessary notifications but that shouldn't be a
+ // problem.
+ synchronized (mListeners) {
+ final int listenerCount = mListeners.size();
+ for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+ ITimeDetectorListener listener = mListeners.valueAt(listenerIndex);
+ try {
+ listener.onChange();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to notify listener=" + listener, e);
+ }
+ }
+ }
}
@Override
@@ -141,11 +274,12 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
enforceSuggestManualTimePermission();
Objects.requireNonNull(timeSignal);
- final long token = Binder.clearCallingIdentity();
+ int userId = mCallerIdentityInjector.getCallingUserId();
+ final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeDetectorStrategy.suggestManualTime(timeSignal);
+ return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal);
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -226,5 +360,4 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
"manage time and time zone detection");
}
-
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
index 721986bc6e93..adc416bf7d75 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
@@ -17,14 +17,26 @@ package com.android.server.timedetector;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_EXTERNAL_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_GNSS_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_NETWORK_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE;
import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE;
+import android.app.time.ExternalTimeSuggestion;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
/** Implements the shell command interface for {@link TimeDetectorService}. */
class TimeDetectorShellCommand extends ShellCommand {
@@ -44,6 +56,16 @@ class TimeDetectorShellCommand extends ShellCommand {
switch (cmd) {
case SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED:
return runIsAutoDetectionEnabled();
+ case SHELL_COMMAND_SUGGEST_MANUAL_TIME:
+ return runSuggestManualTime();
+ case SHELL_COMMAND_SUGGEST_TELEPHONY_TIME:
+ return runSuggestTelephonyTime();
+ case SHELL_COMMAND_SUGGEST_NETWORK_TIME:
+ return runSuggestNetworkTime();
+ case SHELL_COMMAND_SUGGEST_GNSS_TIME:
+ return runSuggestGnssTime();
+ case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME:
+ return runSuggestExternalTime();
default: {
return handleDefaultCommands(cmd);
}
@@ -53,12 +75,59 @@ class TimeDetectorShellCommand extends ShellCommand {
private int runIsAutoDetectionEnabled() {
final PrintWriter pw = getOutPrintWriter();
boolean enabled = mInterface.getCapabilitiesAndConfig()
- .getTimeConfiguration()
+ .getConfiguration()
.isAutoDetectionEnabled();
pw.println(enabled);
return 0;
}
+ private int runSuggestManualTime() {
+ return runSuggestTime(
+ () -> ManualTimeSuggestion.parseCommandLineArg(this),
+ mInterface::suggestManualTime);
+ }
+
+ private int runSuggestTelephonyTime() {
+ return runSuggestTime(
+ () -> TelephonyTimeSuggestion.parseCommandLineArg(this),
+ mInterface::suggestTelephonyTime);
+ }
+
+ private int runSuggestNetworkTime() {
+ return runSuggestTime(
+ () -> NetworkTimeSuggestion.parseCommandLineArg(this),
+ mInterface::suggestNetworkTime);
+ }
+
+ private int runSuggestGnssTime() {
+ return runSuggestTime(
+ () -> GnssTimeSuggestion.parseCommandLineArg(this),
+ mInterface::suggestGnssTime);
+ }
+
+ private int runSuggestExternalTime() {
+ return runSuggestTime(
+ () -> ExternalTimeSuggestion.parseCommandLineArg(this),
+ mInterface::suggestExternalTime);
+ }
+
+ private <T> int runSuggestTime(Supplier<T> suggestionParser, Consumer<T> invoker) {
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ T suggestion = suggestionParser.get();
+ if (suggestion == null) {
+ pw.println("Error: suggestion not specified");
+ return 1;
+ }
+ invoker.accept(suggestion);
+ pw.println("Suggestion " + suggestion + " injected.");
+ return 0;
+ } catch (RuntimeException e) {
+ pw.println(e);
+ return 1;
+ }
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -68,6 +137,22 @@ class TimeDetectorShellCommand extends ShellCommand {
pw.printf(" %s\n", SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED);
pw.printf(" Prints true/false according to the automatic time detection setting.\n");
pw.println();
+ pw.printf(" %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME);
+ pw.printf(" %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME);
+ pw.printf(" %s <network suggestion opts>\n", SHELL_COMMAND_SUGGEST_NETWORK_TIME);
+ pw.printf(" %s <gnss suggestion opts>\n", SHELL_COMMAND_SUGGEST_GNSS_TIME);
+ pw.printf(" %s <external suggestion opts>\n", SHELL_COMMAND_SUGGEST_EXTERNAL_TIME);
+ pw.println();
+ ManualTimeSuggestion.printCommandLineOpts(pw);
+ pw.println();
+ TelephonyTimeSuggestion.printCommandLineOpts(pw);
+ pw.println();
+ NetworkTimeSuggestion.printCommandLineOpts(pw);
+ pw.println();
+ GnssTimeSuggestion.printCommandLineOpts(pw);
+ pw.println();
+ ExternalTimeSuggestion.printCommandLineOpts(pw);
+ pw.println();
pw.printf("This service is also affected by the following device_config flags in the"
+ " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
pw.printf(" %s\n", KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index acabb6e393a8..cec383ce77be 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -76,7 +76,7 @@ public interface TimeDetectorStrategy extends Dumpable {
* suggestion was accepted. A suggestion that is valid but does not change the time because it
* matches the current device time is considered accepted.
*/
- boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+ boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion timeSuggestion);
/** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
@@ -87,9 +87,6 @@ public interface TimeDetectorStrategy extends Dumpable {
/** Processes the suggested time from external sources. */
void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion);
- /** Returns the configuration that controls time detector behaviour for specified user. */
- ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
-
// Utility methods below are to be moved to a better home when one becomes more obvious.
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 74660012e49c..ecbf1f88c120 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -18,8 +18,8 @@ package com.android.server.timedetector;
import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
-import static java.util.stream.Collectors.joining;
-
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -86,6 +86,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
*/
private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10;
+ /** The value in Unix epoch milliseconds of the Y2038 issue. */
+ private static final long Y2038_LIMIT_IN_MILLIS = 1000L * Integer.MAX_VALUE;
+
/**
* A log that records the decisions / decision metadata that affected the device's system clock
* time. This is logged in bug reports to assist with debugging issues with detection.
@@ -96,6 +99,10 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@NonNull
private final Environment mEnvironment;
+ @GuardedBy("this")
+ @NonNull
+ private ConfigurationInternal mCurrentConfigurationInternal;
+
// Used to store the last time the system clock state was set automatically. It is used to
// detect (and log) issues with the realtime clock or whether the clock is being set without
// going through this strategy code.
@@ -125,64 +132,38 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
/**
- * The interface used by the strategy to interact with the surrounding service.
+ * Used by {@link TimeDetectorStrategyImpl} to interact with device configuration / settings
+ * / system properties. It can be faked for testing.
*
- * <p>Note: Because the system properties-derived value {@link #isAutoTimeDetectionEnabled()}
- * can be modified independently and from different threads (and processes!), its use is prone
- * to race conditions. That will be true until the responsibility for setting their values is
- * moved to {@link TimeDetectorStrategy}. There are similar issues with
- * {@link #systemClockMillis()} while any process can modify the system clock.
+ * <p>Note: Because the settings / system properties-derived values can currently be modified
+ * independently and from different threads (and processes!), their use is prone to race
+ * conditions.
*/
public interface Environment {
/**
* Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
- * changes that could affect time detection. This is invoked during system server setup.
- */
- void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
-
- /**
- * The absolute threshold below which the system clock need not be updated. i.e. if setting
- * the system clock would adjust it by less than this (either backwards or forwards) then it
- * need not be set.
- */
- int systemClockUpdateThresholdMillis();
-
- /** Returns true if automatic time detection is enabled. */
- boolean isAutoTimeDetectionEnabled();
-
- /**
- * Returns a lower bound for valid automatic times. It is guaranteed to be in the past,
- * i.e. it is unrelated to the current system clock time.
- * It holds no other meaning; it could be related to when the device system image was built,
- * or could be updated by a mainline module.
- */
- @NonNull
- Instant autoTimeLowerBound();
-
- /**
- * Returns the order to look at time suggestions when automatically detecting time.
- * See {@code #ORIGIN_} constants
+ * changes that could affect the content of {@link ConfigurationInternal}.
+ * This is invoked during system server setup.
*/
- @Origin int[] autoOriginPriorities();
+ void setConfigurationInternalChangeListener(@NonNull ConfigurationChangeListener listener);
- /**
- * Returns {@link ConfigurationInternal} for specified user.
- */
- @NonNull
- ConfigurationInternal configurationInternal(@UserIdInt int userId);
+ /** Returns the {@link ConfigurationInternal} for the current user. */
+ @NonNull ConfigurationInternal getCurrentUserConfigurationInternal();
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
/** Returns the elapsedRealtimeMillis clock value. */
+ @ElapsedRealtimeLong
long elapsedRealtimeMillis();
/** Returns the system clock value. */
+ @CurrentTimeMillisLong
long systemClockMillis();
/** Sets the device system clock. The WakeLock must be held. */
- void setSystemClock(long newTimeMillis);
+ void setSystemClock(@CurrentTimeMillisLong long newTimeMillis);
/** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
void releaseWakeLock();
@@ -200,39 +181,73 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@VisibleForTesting
TimeDetectorStrategyImpl(@NonNull Environment environment) {
mEnvironment = Objects.requireNonNull(environment);
- mEnvironment.setConfigChangeListener(this::handleAutoTimeConfigChanged);
+
+ synchronized (this) {
+ mEnvironment.setConfigurationInternalChangeListener(
+ this::handleConfigurationInternalChanged);
+ mCurrentConfigurationInternal = mEnvironment.getCurrentUserConfigurationInternal();
+ }
}
@Override
- public synchronized void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion) {
- final TimestampedValue<Long> newUnixEpochTime = timeSuggestion.getUnixEpochTime();
+ public synchronized void suggestExternalTime(@NonNull ExternalTimeSuggestion suggestion) {
+ ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
+ if (DBG) {
+ Slog.d(LOG_TAG, "External suggestion received."
+ + " currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
+ }
+ Objects.requireNonNull(suggestion);
+
+ final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime();
- if (!validateAutoSuggestionTime(newUnixEpochTime, timeSuggestion)) {
+ if (!validateAutoSuggestionTime(newUnixEpochTime, suggestion)) {
return;
}
- mLastExternalSuggestion.set(timeSuggestion);
+ mLastExternalSuggestion.set(suggestion);
- String reason = "External time suggestion received: suggestion=" + timeSuggestion;
+ String reason = "External time suggestion received: suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@Override
- public synchronized void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion) {
- final TimestampedValue<Long> newUnixEpochTime = timeSuggestion.getUnixEpochTime();
+ public synchronized void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion) {
+ ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
+ if (DBG) {
+ Slog.d(LOG_TAG, "GNSS suggestion received."
+ + " currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
+ }
+ Objects.requireNonNull(suggestion);
+
+ final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime();
- if (!validateAutoSuggestionTime(newUnixEpochTime, timeSuggestion)) {
+ if (!validateAutoSuggestionTime(newUnixEpochTime, suggestion)) {
return;
}
- mLastGnssSuggestion.set(timeSuggestion);
+ mLastGnssSuggestion.set(suggestion);
- String reason = "GNSS time suggestion received: suggestion=" + timeSuggestion;
+ String reason = "GNSS time suggestion received: suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@Override
- public synchronized boolean suggestManualTime(@NonNull ManualTimeSuggestion suggestion) {
+ public synchronized boolean suggestManualTime(
+ @UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion) {
+
+ ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
+ if (currentUserConfig.getUserId() != userId) {
+ Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId
+ + " suggestion=" + suggestion);
+
+ // Only listen to changes from the current user.
+ return false;
+ }
+
+ Objects.requireNonNull(suggestion);
+
final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime();
if (!validateSuggestionTime(newUnixEpochTime, suggestion)) {
@@ -244,8 +259,16 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@Override
- public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) {
- if (!validateAutoSuggestionTime(timeSuggestion.getUnixEpochTime(), timeSuggestion)) {
+ public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
+ ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
+ if (DBG) {
+ Slog.d(LOG_TAG, "Network suggestion received."
+ + " currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
+ }
+ Objects.requireNonNull(suggestion);
+
+ if (!validateAutoSuggestionTime(suggestion.getUnixEpochTime(), suggestion)) {
return;
}
@@ -257,13 +280,13 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
// the suggestion and device state are always re-evaluated, which might produce a different
// detected time if, for example, the age of all suggestions are considered.
NetworkTimeSuggestion lastNetworkSuggestion = mLastNetworkSuggestion.get();
- if (lastNetworkSuggestion == null || !lastNetworkSuggestion.equals(timeSuggestion)) {
- mLastNetworkSuggestion.set(timeSuggestion);
+ if (lastNetworkSuggestion == null || !lastNetworkSuggestion.equals(suggestion)) {
+ mLastNetworkSuggestion.set(suggestion);
}
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
- String reason = "New network time suggested. timeSuggestion=" + timeSuggestion;
+ String reason = "New network time suggested. timeSuggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@@ -294,17 +317,20 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
doAutoTimeDetection(reason);
}
- @Override
- @NonNull
- public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
- return mEnvironment.configurationInternal(userId);
- }
+ private synchronized void handleConfigurationInternalChanged() {
+ ConfigurationInternal currentUserConfig =
+ mEnvironment.getCurrentUserConfigurationInternal();
+ String logMsg = "handleConfigurationInternalChanged:"
+ + " oldConfiguration=" + mCurrentConfigurationInternal
+ + ", newConfiguration=" + currentUserConfig;
+ logTimeDetectorChange(logMsg);
+ mCurrentConfigurationInternal = currentUserConfig;
- private synchronized void handleAutoTimeConfigChanged() {
- boolean enabled = mEnvironment.isAutoTimeDetectionEnabled();
+ boolean autoDetectionEnabled =
+ mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior();
// When automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, when automatic time detection is disabled we leave the clock as it is.
- if (enabled) {
+ if (autoDetectionEnabled) {
String reason = "Auto time zone detection config changed.";
doAutoTimeDetection(reason);
} else {
@@ -314,30 +340,27 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
}
+ private void logTimeDetectorChange(@NonNull String logMsg) {
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
+ }
+ mTimeChangesLog.log(logMsg);
+ }
+
@Override
public synchronized void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
ipw.println("TimeDetectorStrategy:");
ipw.increaseIndent(); // level 1
ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
- ipw.println("mEnvironment.isAutoTimeDetectionEnabled()="
- + mEnvironment.isAutoTimeDetectionEnabled());
+ ipw.println("mCurrentConfigurationInternal=" + mCurrentConfigurationInternal);
+ ipw.println("[Capabilities=" + mCurrentConfigurationInternal.capabilitiesAndConfig() + "]");
long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
ipw.printf("mEnvironment.elapsedRealtimeMillis()=%s (%s)\n",
Duration.ofMillis(elapsedRealtimeMillis), elapsedRealtimeMillis);
long systemClockMillis = mEnvironment.systemClockMillis();
ipw.printf("mEnvironment.systemClockMillis()=%s (%s)\n",
Instant.ofEpochMilli(systemClockMillis), systemClockMillis);
- ipw.println("mEnvironment.systemClockUpdateThresholdMillis()="
- + mEnvironment.systemClockUpdateThresholdMillis());
- Instant autoTimeLowerBound = mEnvironment.autoTimeLowerBound();
- ipw.printf("mEnvironment.autoTimeLowerBound()=%s (%s)\n",
- autoTimeLowerBound, autoTimeLowerBound.toEpochMilli());
- String priorities =
- Arrays.stream(mEnvironment.autoOriginPriorities())
- .mapToObj(TimeDetectorStrategy::originToString)
- .collect(joining(",", "[", "]"));
- ipw.println("mEnvironment.autoOriginPriorities()=" + priorities);
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
@@ -402,6 +425,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
return true;
}
+ @GuardedBy("this")
private boolean validateSuggestionTime(
@NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) {
if (newUnixEpochTime.getValue() == null) {
@@ -418,18 +442,30 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
+ ", suggestion=" + suggestion);
return false;
}
+
+ if (newUnixEpochTime.getValue() > Y2038_LIMIT_IN_MILLIS
+ && mCurrentConfigurationInternal.getDeviceHasY2038Issue()) {
+ // This check won't prevent a device's system clock exceeding Integer.MAX_VALUE Unix
+ // seconds through the normal passage of time, but it will stop it jumping above 2038
+ // because of a "bad" suggestion. b/204193177
+ Slog.w(LOG_TAG, "Suggested value is above max time supported by this device."
+ + " suggestion=" + suggestion);
+ return false;
+ }
return true;
}
+ @GuardedBy("this")
private boolean validateAutoSuggestionTime(
@NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) {
return validateSuggestionTime(newUnixEpochTime, suggestion)
&& validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion);
}
+ @GuardedBy("this")
private boolean validateSuggestionAgainstLowerBound(
@NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) {
- Instant lowerBound = mEnvironment.autoTimeLowerBound();
+ Instant lowerBound = mCurrentConfigurationInternal.getAutoTimeLowerBound();
// Suggestion is definitely wrong if it comes before lower time bound.
if (lowerBound.isAfter(Instant.ofEpochMilli(newUnixEpochTime.getValue()))) {
@@ -443,13 +479,13 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@GuardedBy("this")
private void doAutoTimeDetection(@NonNull String detectionReason) {
- if (!mEnvironment.isAutoTimeDetectionEnabled()) {
+ if (!mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
// Avoid doing unnecessary work with this (race-prone) check.
return;
}
// Try the different origins one at a time.
- int[] originPriorities = mEnvironment.autoOriginPriorities();
+ int[] originPriorities = mCurrentConfigurationInternal.getAutoOriginPriorities();
for (int origin : originPriorities) {
TimestampedValue<Long> newUnixEpochTime = null;
String cause = null;
@@ -672,7 +708,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
- if (!mEnvironment.isAutoTimeDetectionEnabled()) {
+ if (!mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is not enabled."
+ " origin=" + originToString(origin)
@@ -682,7 +718,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
return false;
}
} else {
- if (mEnvironment.isAutoTimeDetectionEnabled()) {
+ if (mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is enabled."
+ " origin=" + originToString(origin)
@@ -739,7 +775,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
// Check if the new signal would make sufficient difference to the system clock. If it's
// below the threshold then ignore it.
long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
- long systemClockUpdateThreshold = mEnvironment.systemClockUpdateThresholdMillis();
+ long systemClockUpdateThreshold =
+ mCurrentConfigurationInternal.getSystemClockUpdateThresholdMillis();
if (absTimeDifference < systemClockUpdateThreshold) {
if (DBG) {
Slog.d(LOG_TAG, "Not setting system clock. New time and"
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index ef4e42a6a8d3..ef99d616cbec 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -24,6 +24,7 @@ import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.time.Capabilities.CapabilityState;
import android.app.time.TimeZoneCapabilities;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
@@ -205,7 +206,7 @@ public final class ConfigurationInternal {
// network available or geolocation time zone detection is possible.
boolean deviceHasAutoTimeZoneDetection = isAutoDetectionSupported();
- final int configureAutoDetectionEnabledCapability;
+ final @CapabilityState int configureAutoDetectionEnabledCapability;
if (!deviceHasAutoTimeZoneDetection) {
configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
} else if (!allowConfigDateTime) {
@@ -219,7 +220,7 @@ public final class ConfigurationInternal {
// Note: allowConfigDateTime does not restrict the ability to change location time zone
// detection enabled. This is intentional as it has user privacy implications and so it
// makes sense to leave this under a user's control.
- final int configureGeolocationDetectionEnabledCapability;
+ final @CapabilityState int configureGeolocationDetectionEnabledCapability;
if (!deviceHasLocationTimeZoneDetection) {
configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
} else if (!mAutoDetectionEnabledSetting || !getLocationEnabledSetting()) {
@@ -234,7 +235,7 @@ public final class ConfigurationInternal {
// the current logic above, this could lead to a situation where a device hardware does not
// support auto detection, the device has been forced into "auto" mode by an admin and the
// user is unable to disable auto detection.
- final int suggestManualTimeZoneCapability;
+ final @CapabilityState int suggestManualTimeZoneCapability;
if (!allowConfigDateTime) {
suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
} else if (getAutoDetectionEnabledBehavior()) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 898d02e212f4..59db855dcf25 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -196,8 +196,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
boolean updateConfiguration(
@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
- userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, false, "updateConfiguration", null);
+ // Resolve constants like USER_CURRENT to the true user ID as needed.
+ int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, false, "updateConfiguration", null);
enforceManageTimeZoneDetectorPermission();
@@ -205,7 +206,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mServiceConfigAccessor.updateConfiguration(userId, configuration);
+ return mServiceConfigAccessor.updateConfiguration(resolvedUserId, configuration);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 07725038255e..b6ab35169fc4 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -155,8 +155,6 @@ final class TvInputHal implements Handler.Callback {
// Handler.Callback implementation
- private final Queue<Message> mPendingMessageQueue = new LinkedList<>();
-
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index f57a852fe8c5..98dfb009e4ef 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -69,7 +69,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -89,7 +88,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private final TvInputHal mHal = new TvInputHal(this);
private final SparseArray<Connection> mConnections = new SparseArray<>();
private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>();
- private final List<HdmiDeviceInfo> mHdmiDeviceList = new LinkedList<>();
+ private final List<HdmiDeviceInfo> mHdmiDeviceList = new ArrayList<>();
/* A map from a device ID to the matching TV input ID. */
private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>();
/* A map from a HDMI logical address to the matching TV input ID. */
@@ -112,9 +111,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private int mCurrentMaxIndex = 0;
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
- private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
+ private final List<Message> mPendingHdmiDeviceEvents = new ArrayList<>();
- private final List<Message> mPendingTvinputInfoEvents = new LinkedList<>();
+ private final List<Message> mPendingTvinputInfoEvents = new ArrayList<>();
// Calls to mListener should happen here.
private final Handler mHandler = new ListenerHandler();
@@ -234,11 +233,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
} else {
Message msg = mHandler.obtainMessage(ListenerHandler.TVINPUT_INFO_ADDED,
deviceId, cableConnectionStatus, connection);
- for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext();) {
- if (it.next().arg1 == deviceId) {
- it.remove();
- }
- }
+ mPendingTvinputInfoEvents.removeIf(message -> message.arg1 == deviceId);
mPendingTvinputInfoEvents.add(msg);
}
ITvInputHardwareCallback callback = connection.getCallbackLocked();
diff --git a/services/core/java/com/android/server/uri/UriPermissionOwner.java b/services/core/java/com/android/server/uri/UriPermissionOwner.java
index 0c263997a8b5..d22bb58f6ded 100644
--- a/services/core/java/com/android/server/uri/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/uri/UriPermissionOwner.java
@@ -30,7 +30,9 @@ import com.android.server.am.UriPermissionOwnerProto;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
public class UriPermissionOwner {
private final UriGrantsManagerInternal mService;
@@ -61,7 +63,7 @@ public class UriPermissionOwner {
static UriPermissionOwner fromExternalToken(IBinder token) {
if (token instanceof ExternalToken) {
- return ((ExternalToken)token).getOwner();
+ return ((ExternalToken) token).getOwner();
}
return null;
}
@@ -79,99 +81,121 @@ public class UriPermissionOwner {
}
void removeUriPermission(GrantUri grantUri, int mode, String targetPgk, int targetUserId) {
- if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) {
- Iterator<UriPermission> it = mReadPerms.iterator();
- while (it.hasNext()) {
- UriPermission perm = it.next();
- if (grantUri != null && !grantUri.equals(perm.uri)) {
- continue;
+ final List<UriPermission> permissionsToRemove = new ArrayList<>();
+
+ synchronized (this) {
+ if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) {
+ final Iterator<UriPermission> it = mReadPerms.iterator();
+ while (it.hasNext()) {
+ final UriPermission perm = it.next();
+ if (grantUri != null && !grantUri.equals(perm.uri)) {
+ continue;
+ }
+ if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) {
+ continue;
+ }
+ if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) {
+ continue;
+ }
+ permissionsToRemove.add(perm);
+ perm.removeReadOwner(this);
+ it.remove();
}
- if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) {
- continue;
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
}
- if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) {
- continue;
- }
- perm.removeReadOwner(this);
- mService.removeUriPermissionIfNeeded(perm);
- it.remove();
- }
- if (mReadPerms.isEmpty()) {
- mReadPerms = null;
}
- }
- if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0 && mWritePerms != null) {
- Iterator<UriPermission> it = mWritePerms.iterator();
- while (it.hasNext()) {
- UriPermission perm = it.next();
- if (grantUri != null && !grantUri.equals(perm.uri)) {
- continue;
- }
- if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) {
- continue;
+
+ if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0 && mWritePerms != null) {
+ final Iterator<UriPermission> it = mWritePerms.iterator();
+ while (it.hasNext()) {
+ final UriPermission perm = it.next();
+ if (grantUri != null && !grantUri.equals(perm.uri)) {
+ continue;
+ }
+ if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) {
+ continue;
+ }
+ if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) {
+ continue;
+ }
+ permissionsToRemove.add(perm);
+ perm.removeWriteOwner(this);
+ it.remove();
}
- if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) {
- continue;
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
}
- perm.removeWriteOwner(this);
- mService.removeUriPermissionIfNeeded(perm);
- it.remove();
- }
- if (mWritePerms.isEmpty()) {
- mWritePerms = null;
}
}
+
+ final int permissionsToRemoveSize = permissionsToRemove.size();
+ for (int i = 0; i < permissionsToRemoveSize; i++) {
+ mService.removeUriPermissionIfNeeded(permissionsToRemove.get(i));
+ }
}
public void addReadPermission(UriPermission perm) {
- if (mReadPerms == null) {
- mReadPerms = Sets.newArraySet();
+ synchronized (this) {
+ if (mReadPerms == null) {
+ mReadPerms = Sets.newArraySet();
+ }
+ mReadPerms.add(perm);
}
- mReadPerms.add(perm);
}
public void addWritePermission(UriPermission perm) {
- if (mWritePerms == null) {
- mWritePerms = Sets.newArraySet();
+ synchronized (this) {
+ if (mWritePerms == null) {
+ mWritePerms = Sets.newArraySet();
+ }
+ mWritePerms.add(perm);
}
- mWritePerms.add(perm);
}
public void removeReadPermission(UriPermission perm) {
- mReadPerms.remove(perm);
- if (mReadPerms.isEmpty()) {
- mReadPerms = null;
+ synchronized (this) {
+ mReadPerms.remove(perm);
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
+ }
}
}
public void removeWritePermission(UriPermission perm) {
- mWritePerms.remove(perm);
- if (mWritePerms.isEmpty()) {
- mWritePerms = null;
+ synchronized (this) {
+ mWritePerms.remove(perm);
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
+ }
}
}
public void dump(PrintWriter pw, String prefix) {
- if (mReadPerms != null) {
- pw.print(prefix); pw.print("readUriPermissions="); pw.println(mReadPerms);
- }
- if (mWritePerms != null) {
- pw.print(prefix); pw.print("writeUriPermissions="); pw.println(mWritePerms);
+ synchronized (this) {
+ if (mReadPerms != null) {
+ pw.print(prefix);
+ pw.print("readUriPermissions=");
+ pw.println(mReadPerms);
+ }
+ if (mWritePerms != null) {
+ pw.print(prefix);
+ pw.print("writeUriPermissions=");
+ pw.println(mWritePerms);
+ }
}
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(UriPermissionOwnerProto.OWNER, mOwner.toString());
- if (mReadPerms != null) {
- synchronized (mReadPerms) {
+ synchronized (this) {
+ if (mReadPerms != null) {
for (UriPermission p : mReadPerms) {
p.uri.dumpDebug(proto, UriPermissionOwnerProto.READ_PERMS);
}
}
- }
- if (mWritePerms != null) {
- synchronized (mWritePerms) {
+ if (mWritePerms != null) {
for (UriPermission p : mWritePerms) {
p.uri.dumpDebug(proto, UriPermissionOwnerProto.WRITE_PERMS);
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index f6748de660e2..47aa58751900 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -737,7 +737,7 @@ class ActivityClientController extends IActivityClientController.Stub {
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"enterPictureInPictureMode", token, params);
- return mService.enterPictureInPictureMode(r, params);
+ return mService.enterPictureInPictureMode(r, params, true /* fromClient */);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -853,22 +853,23 @@ class ActivityClientController extends IActivityClientController.Stub {
/**
* Requests that an activity should enter picture-in-picture mode if possible. This method may
* be used by the implementation of non-phone form factors.
+ *
+ * @return false if the activity cannot enter PIP mode.
*/
- void requestPictureInPictureMode(@NonNull ActivityRecord r) {
+ boolean requestPictureInPictureMode(@NonNull ActivityRecord r) {
if (r.inPinnedWindowingMode()) {
- throw new IllegalStateException("Activity is already in PIP mode");
+ return false;
}
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"requestPictureInPictureMode", /* beforeStopping */ false);
if (!canEnterPictureInPicture) {
- throw new IllegalStateException(
- "Requested PIP on an activity that doesn't support it");
+ return false;
}
if (r.pictureInPictureArgs.isAutoEnterEnabled()) {
- mService.enterPictureInPictureMode(r, r.pictureInPictureArgs);
- return;
+ return mService.enterPictureInPictureMode(r, r.pictureInPictureArgs,
+ false /* fromClient */);
}
try {
@@ -876,9 +877,11 @@ class ActivityClientController extends IActivityClientController.Stub {
r.app.getThread(), r.token);
transaction.addCallback(EnterPipRequestedItem.obtain());
mService.getLifecycleManager().scheduleTransaction(transaction);
+ return true;
} catch (Exception e) {
Slog.w(TAG, "Failed to send enter pip requested item: "
+ r.intent.getComponent(), e);
+ return false;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index d6c0ab6b124b..622de57a1078 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -68,6 +68,7 @@ import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
@@ -101,6 +102,7 @@ import android.util.TimeUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -780,6 +782,12 @@ class ActivityMetricsLogger {
info.mReason = activityToReason.valueAt(index);
info.mLoggedTransitionStarting = true;
if (info.mIsDrawn) {
+ if (info.mReason == APP_TRANSITION_RECENTS_ANIM) {
+ final LatencyTracker latencyTracker = r.mWmService.mLatencyTracker;
+ final int duration = info.mSourceEventDelayMs + info.mCurrentTransitionDelayMs;
+ mLoggerHandler.post(() -> latencyTracker.logAction(
+ LatencyTracker.ACTION_START_RECENTS_ANIMATION, duration));
+ }
done(false /* abort */, info, "notifyTransitionStarting drawn", timestampNs);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d73746c077ca..cd40f7454cd5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -432,6 +432,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private static final int DESTROY_TIMEOUT = 10 * 1000;
final ActivityTaskManagerService mAtmService;
+ @NonNull
final ActivityInfo info; // activity info provided by developer in AndroidManifest
// Which user is this running for?
final int mUserId;
@@ -873,7 +874,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mEnteringAnimation;
boolean mOverrideTaskTransition;
- boolean mDismissKeyguardIfInsecure;
+ boolean mDismissKeyguard;
boolean mAppStopped;
// A hint to override the window specified rotation animation, or -1 to use the window specified
@@ -1992,7 +1993,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
mOverrideTaskTransition = options.getOverrideTaskTransition();
- mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure();
+ mDismissKeyguard = options.getDismissKeyguard();
}
ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
@@ -2786,7 +2787,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting
boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
- if (uid == Process.myUid() || uid == 0) {
+ if (uid == SYSTEM_UID || uid == 0) {
// System process can launch home activity.
return true;
}
@@ -3000,25 +3001,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
&& info.supportsPictureInPicture();
}
- /**
- * @return whether this activity supports split-screen multi-window and can be put in
- * split-screen.
- */
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- return supportsSplitScreenWindowingModeInDisplayArea(getDisplayArea());
- }
-
- /**
- * @return whether this activity supports split-screen multi-window and can be put in
- * split-screen if it is in the given {@link TaskDisplayArea}.
- */
- boolean supportsSplitScreenWindowingModeInDisplayArea(@Nullable TaskDisplayArea tda) {
- return super.supportsSplitScreenWindowingMode()
- && mAtmService.mSupportsSplitScreenMultiWindow
- && supportsMultiWindowInDisplayArea(tda);
- }
-
boolean supportsFreeform() {
return supportsFreeformInDisplayArea(getDisplayArea());
}
@@ -4469,12 +4451,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* @return Whether we are allowed to show non-starting windows at the moment. We disallow
- * showing windows during transitions in case we have windows that have wide-color-gamut
- * color mode set to avoid jank in the middle of the transition.
+ * showing windows while the transition animation is playing in case we have windows
+ * that have wide-color-gamut color mode set to avoid jank in the middle of the
+ * animation.
*/
boolean canShowWindows() {
- return allDrawn && !(isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)
- && hasNonDefaultColorWindow());
+ final boolean drawn = mTransitionController.isShellTransitionsEnabled()
+ ? mSyncState != SYNC_STATE_WAITING_FOR_DRAW : allDrawn;
+ final boolean animating = mTransitionController.isShellTransitionsEnabled()
+ ? mTransitionController.inPlayingTransition(this)
+ : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION);
+ return drawn && !(animating && hasNonDefaultColorWindow());
}
/**
@@ -5530,7 +5517,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
wasStopped, this);
mAppStopped = false;
// Allow the window to turn the screen on once the app is resumed again.
- setCurrentLaunchCanTurnScreenOn(true);
+ if (mAtmService.getActivityStartController().isInExecution()) {
+ setCurrentLaunchCanTurnScreenOn(true);
+ }
+
if (!wasStopped) {
destroySurfaces(true /*cleanupOnResume*/);
}
@@ -7734,7 +7724,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
// In fullscreen, can be letterboxed for aspect ratio.
|| !inMultiWindowMode()) {
- updateResolvedBoundsHorizontalPosition(newParentConfiguration);
+ updateResolvedBoundsPosition(newParentConfiguration);
}
if (mVisibleRequested) {
@@ -7837,39 +7827,60 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
+ * Adjusts position of resolved bounds if they doesn't fill the parent using gravity
* requested in the config or via an ADB command. For more context see {@link
- * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)}.
+ * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
+ * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
*/
- private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) {
+ private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
final Rect screenResolvedBounds =
mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- if (resolvedBounds.isEmpty() || parentBounds.width() == screenResolvedBounds.width()) {
+ if (resolvedBounds.isEmpty()) {
return;
}
-
+ // Horizontal position
int offsetX = 0;
- if (screenResolvedBounds.width() >= parentAppBounds.width()) {
- // If resolved bounds overlap with insets, center within app bounds.
- offsetX = getHorizontalCenterOffset(
- parentAppBounds.width(), screenResolvedBounds.width());
- } else {
- float positionMultiplier =
- mLetterboxUiController.getHorizontalPositionMultiplier(newParentConfiguration);
- offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
- * positionMultiplier);
+ if (parentBounds.width() != screenResolvedBounds.width()) {
+ if (screenResolvedBounds.width() >= parentAppBounds.width()) {
+ // If resolved bounds overlap with insets, center within app bounds.
+ offsetX = getCenterOffset(
+ parentAppBounds.width(), screenResolvedBounds.width());
+ } else {
+ float positionMultiplier =
+ mLetterboxUiController.getHorizontalPositionMultiplier(
+ newParentConfiguration);
+ offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
+ * positionMultiplier);
+ }
+ }
+
+ // Vertical position
+ int offsetY = 0;
+ if (parentBounds.height() != screenResolvedBounds.height()) {
+ if (screenResolvedBounds.height() >= parentAppBounds.height()) {
+ // If resolved bounds overlap with insets, center within app bounds.
+ offsetY = getCenterOffset(
+ parentAppBounds.height(), screenResolvedBounds.height());
+ } else {
+ float positionMultiplier =
+ mLetterboxUiController.getVerticalPositionMultiplier(
+ newParentConfiguration);
+ offsetY = (int) Math.ceil((parentAppBounds.height() - screenResolvedBounds.height())
+ * positionMultiplier);
+ }
}
if (mSizeCompatBounds != null) {
- mSizeCompatBounds.offset(offsetX, 0 /* offsetY */);
+ mSizeCompatBounds.offset(offsetX , offsetY);
+ final int dy = mSizeCompatBounds.top - resolvedBounds.top;
final int dx = mSizeCompatBounds.left - resolvedBounds.left;
- offsetBounds(resolvedConfig, dx, 0 /* offsetY */);
+ offsetBounds(resolvedConfig, dx, dy);
} else {
- offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
+ offsetBounds(resolvedConfig, offsetX, offsetY);
}
// Since bounds has changed, the configuration needs to be computed accordingly.
@@ -7897,6 +7908,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
}
+ boolean isAspectRatioApplied() {
+ return mIsAspectRatioApplied;
+ }
+
/**
* Whether this activity is eligible for letterbox eduction.
*
@@ -8068,21 +8083,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedBounds.set(containingBounds);
final float letterboxAspectRatioOverride =
- mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
+ mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
final float desiredAspectRatio =
letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
// Apply aspect ratio to resolved bounds
mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
- containingBounds, desiredAspectRatio, true);
-
- // Vertically center if orientation is landscape. Center within parent bounds with insets
- // to ensure that insets do not trim height. Bounds will later be horizontally centered in
- // {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
- if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
- resolvedBounds.offset(0, offsetY);
- }
+ containingBounds, desiredAspectRatio);
if (mCompatDisplayInsets != null) {
mCompatDisplayInsets.getBoundsByRotation(
@@ -8106,10 +8113,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
- * aspect ratio, the position will be adjusted later in {@link
- * updateResolvedBoundsHorizontalPosition} within parent's app bounds to balance the visual
- * appearance. The policy of aspect ratio has higher priority than the requested override
- * bounds.
+ * aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
+ * within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
+ * higher priority than the requested override bounds.
*/
private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
@@ -8121,7 +8127,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTmpBounds.setEmpty();
mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
// If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
- // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
+ // then they should be aligned later in #updateResolvedBoundsPosition()
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
}
@@ -8255,22 +8261,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
}
- // Vertically center within parent (bounds) - this is a UX choice and exclude the horizontal
- // decor if needed. Horizontal position is adjusted in
- // updateResolvedBoundsHorizontalPosition.
+ // The position will be later adjusted in updateResolvedBoundsPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
- // If the activity is not in size compat mode, calculate vertical centering
- // from the container and resolved bounds.
- // If the activity is in size compat mode, calculate vertical centering
- // from the container and size compat bounds.
- // The container bounds contain the parent bounds offset in the display, for
- // example when an activity is in the lower split of split screen.
- final int screenPosY = (mSizeCompatBounds == null
- ? (containerBounds.height() - resolvedBounds.height()) / 2
- : (containerBounds.height() - mSizeCompatBounds.height()) / 2)
- + containerBounds.top;
+ final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
@@ -8330,9 +8325,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
- /** @return The horizontal offset of putting the content in the center of viewport. */
- private static int getHorizontalCenterOffset(int viewportW, int contentW) {
- return (int) ((viewportW - contentW + 1) * 0.5f);
+ /** @return The horizontal / vertical offset of putting the content in the center of viewport.*/
+ private static int getCenterOffset(int viewportDim, int contentDim) {
+ return (int) ((viewportDim - contentDim + 1) * 0.5f);
}
private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
@@ -8520,7 +8515,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
Rect containingBounds) {
return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
- 0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
+ 0 /* desiredAspectRatio */);
}
/**
@@ -8531,23 +8526,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
+ Rect containingBounds, float desiredAspectRatio) {
final float maxAspectRatio = info.getMaxAspectRatio();
final Task rootTask = getRootTask();
final float minAspectRatio = getMinAspectRatio();
- // Not using ActivityRecord#isResizeable() directly because app compatibility testing
- // showed that android:supportsPictureInPicture="true" alone is not sufficient signal for
- // not letterboxing an app.
- // TODO(214602463): Remove multi-window check since orientation and aspect ratio
- // restrictions should always be applied in multi-window.
+ final TaskFragment organizedTf = getOrganizedTaskFragment();
if (task == null || rootTask == null
- || (inMultiWindowMode() && isResizeable(/* checkPictureInPictureSupport */ false)
- && !fixedOrientationLetterboxed)
|| (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
- || isInVrUiMode(getConfiguration())) {
- // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
- // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
- // are in VR mode.
+ // Don't set aspect ratio if we are in VR mode.
+ || isInVrUiMode(getConfiguration())
+ // TODO(b/232898850): Always respect aspect ratio requests.
+ // Don't set aspect ratio for activity in ActivityEmbedding split.
+ || (organizedTf != null && !organizedTf.fillsParent())) {
return false;
}
@@ -8646,7 +8636,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Returns the min aspect ratio of this activity.
*/
private float getMinAspectRatio() {
- return info.getMinAspectRatio(getRequestedOrientation());
+ float infoAspectRatio = info.getMinAspectRatio(getRequestedOrientation());
+ // Complying with the CDD 7.1.1.2 requirement for unresizble apps:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ return infoAspectRatio < 1f && info.resizeMode == RESIZE_MODE_UNRESIZEABLE
+ // TODO(233582832): Consider removing fixed-orientation condition.
+ // Some apps switching from tablet to phone layout at the certain size
+ // threshold. This may lead to flickering on tablets in landscape orientation
+ // if an app sets orientation to portrait dynamically because of aspect ratio
+ // restriction applied here.
+ && getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
+ ? mLetterboxUiController.getDefaultMinAspectRatioForUnresizableApps()
+ : infoAspectRatio;
}
/**
@@ -9595,7 +9596,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
outBounds.bottom = dH;
outBounds.right = (int) ((float) dH * dH / dW);
}
- outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
+ outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
}
outAppBounds.set(outBounds);
@@ -9675,6 +9676,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
boolean isSyncFinished() {
if (!super.isSyncFinished()) return false;
+ if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
+ .isVisibilityUnknown(this)) {
+ return false;
+ }
if (!isVisibleRequested()) return true;
// Wait for attach. That is the earliest time where we know if there will be an associated
// display rotation. If we don't wait, the starting-window can finishDrawing first and
@@ -9702,6 +9707,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
+ @Nullable
+ Point getMinDimensions() {
+ final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
+ if (windowLayout == null) {
+ return null;
+ }
+ return new Point(windowLayout.minWidth, windowLayout.minHeight);
+ }
+
static class Builder {
private final ActivityTaskManagerService mAtmService;
private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index fc22e2decbef..d59f69622f15 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.os.InputConfig;
-import android.os.Process;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -102,8 +101,8 @@ class ActivityRecordInputSink {
inputWindowHandle.replaceTouchableRegionWithCrop = true;
inputWindowHandle.name = mName;
inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- inputWindowHandle.ownerUid = Process.myUid();
- inputWindowHandle.ownerPid = Process.myPid();
+ inputWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ inputWindowHandle.ownerUid = WindowManagerService.MY_UID;
inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.NO_INPUT_CHANNEL;
return inputWindowHandle;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index d60981fcf504..501d45f1d985 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -90,6 +90,8 @@ public class ActivityStartController {
boolean mCheckedForSetup = false;
+ private boolean mInExecution = false;
+
/**
* TODO(b/64750076): Capture information necessary for dump and
* {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
@@ -123,7 +125,15 @@ public class ActivityStartController {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
+ void onExecutionStarted(ActivityStarter starter) {
+ mInExecution = true;
+ }
+
+ boolean isInExecution() {
+ return mInExecution;
+ }
void onExecutionComplete(ActivityStarter starter) {
+ mInExecution = false;
if (mLastStarter == null) {
mLastStarter = mFactory.obtain();
}
@@ -218,8 +228,8 @@ public class ActivityStartController {
vers = ri.activityInfo.applicationInfo.metaData.getString(
Intent.METADATA_SETUP_VERSION);
}
- String lastVers = Settings.Secure.getString(
- resolver, Settings.Secure.LAST_SETUP_SHOWN);
+ String lastVers = Settings.Secure.getStringForUser(
+ resolver, Settings.Secure.LAST_SETUP_SHOWN, resolver.getUserId());
if (vers != null && !vers.equals(lastVers)) {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
@@ -508,7 +518,8 @@ public class ActivityStartController {
*/
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
- @Nullable IBinder resultTo, int callingUid, int callingPid) {
+ @Nullable IBinder resultTo, int callingUid, int callingPid,
+ @Nullable IBinder errorCallbackToken) {
final ActivityRecord caller =
resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
return obtainStarter(activityIntent, "startActivityInTaskFragment")
@@ -521,6 +532,7 @@ public class ActivityStartController {
.setRealCallingUid(callingUid)
.setRealCallingPid(callingPid)
.setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
+ .setErrorCallbackToken(errorCallbackToken)
.execute();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index fb87576ba809..5fbb2e5792cb 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -51,6 +51,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.launchModeToString;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -89,7 +90,6 @@ import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration;
-import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
@@ -212,6 +212,7 @@ class ActivityStarter {
// The task which was above the targetTask before starting this activity. null if the targetTask
// was already on top or if the activity is in a new task.
private Task mPriorAboveTask;
+ private boolean mDisplayLockAndOccluded;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -369,6 +370,13 @@ class ActivityStarter {
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart;
+ /**
+ * The error callback token passed in {@link android.window.WindowContainerTransaction}
+ * for TaskFragment operation error handling via
+ * {@link android.window.TaskFragmentOrganizer#onTaskFragmentError(IBinder, Throwable)}.
+ */
+ @Nullable
+ IBinder errorCallbackToken;
/**
* If set to {@code true}, allows this activity start to look into
@@ -422,6 +430,7 @@ class ActivityStarter {
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
allowBackgroundActivityStart = false;
+ errorCallbackToken = null;
}
/**
@@ -464,6 +473,7 @@ class ActivityStarter {
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
+ errorCallbackToken = request.errorCallbackToken;
}
/**
@@ -634,6 +644,8 @@ class ActivityStarter {
*/
int execute() {
try {
+ onExecutionStarted();
+
// Refuse possible leaked file descriptors
if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -956,8 +968,8 @@ class ActivityStarter {
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE);
- if (!mService.getPackageManager().activitySupportsIntent(
- intent.getComponent(), intent, resolvedType)) {
+ if (!mService.getPackageManager().activitySupportsIntentAsUser(
+ intent.getComponent(), intent, resolvedType, userId)) {
Slog.w(TAG, "Activity being started in current voice task does not support "
+ "voice: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
@@ -973,8 +985,8 @@ class ActivityStarter {
// If the caller is starting a new voice session, just make sure the target
// is actually allowing it to run this way.
try {
- if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
- intent, resolvedType)) {
+ if (!mService.getPackageManager().activitySupportsIntentAsUser(
+ intent.getComponent(), intent, resolvedType, userId)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
@@ -1248,6 +1260,10 @@ class ActivityStarter {
mController.onExecutionComplete(this);
}
+ private void onExecutionStarted() {
+ mController.onExecutionStarted(this);
+ }
+
private boolean isHomeApp(int uid, @Nullable String packageName) {
if (mService.mHomeProcess != null) {
// Fast check
@@ -1668,6 +1684,7 @@ class ActivityStarter {
private @Nullable Task handleStartResult(@NonNull ActivityRecord started,
ActivityOptions options, int result, Transition newTransition,
RemoteTransition remoteTransition) {
+ final boolean userLeaving = mSupervisor.mUserLeaving;
mSupervisor.mUserLeaving = false;
final Task currentRootTask = started.getRootTask();
final Task startedActivityRootTask =
@@ -1686,7 +1703,8 @@ class ActivityStarter {
// Root task should also be detached from display and be removed if it's empty.
if (startedActivityRootTask != null && startedActivityRootTask.isAttached()
&& !startedActivityRootTask.hasActivity()
- && !startedActivityRootTask.isActivityTypeHome()) {
+ && !startedActivityRootTask.isActivityTypeHome()
+ && !startedActivityRootTask.mCreatedByOrganizer) {
startedActivityRootTask.removeIfPossible("handleStartResult");
}
if (newTransition != null) {
@@ -1727,19 +1745,42 @@ class ActivityStarter {
// Transition housekeeping.
final TransitionController transitionController = started.mTransitionController;
final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT;
+ final boolean isTransientLaunch = options != null && options.getTransientLaunch();
+ // Start transient launch while keyguard locked and occluded by other app, for this
+ // condition we would like to play the remote transition without modify any visible state
+ // for the hierarchy in core, so here will force execute this transition.
+ final boolean forceTransientTransition = isTransientLaunch && mPriorAboveTask != null
+ && mDisplayLockAndOccluded;
if (isStarted) {
// The activity is started new rather than just brought forward, so record it as an
// existence change.
transitionController.collectExistenceChange(started);
} else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
// We just delivered to top, so there isn't an actual transition here.
- newTransition.abort();
- newTransition = null;
+ if (!forceTransientTransition) {
+ newTransition.abort();
+ newTransition = null;
+ }
}
- if (options != null && options.getTransientLaunch()) {
+ if (isTransientLaunch) {
+ if (forceTransientTransition && newTransition != null) {
+ newTransition.collect(mLastStartActivityRecord);
+ newTransition.collect(mPriorAboveTask);
+ }
// `started` isn't guaranteed to be the actual relevant activity, so we must wait
// until after we launched to identify the relevant activity.
transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
+ if (forceTransientTransition && newTransition != null) {
+ final DisplayContent dc = mLastStartActivityRecord.getDisplayContent();
+ // update wallpaper target to TransientHide
+ dc.mWallpaperController.adjustWallpaperWindows();
+ // execute transition because there is no change
+ newTransition.setReady(dc, true /* ready */);
+ }
+ }
+ if (!userLeaving) {
+ // no-user-leaving implies not entering PiP.
+ transitionController.setCanPipOnFinish(false /* canPipOnFinish */);
}
if (newTransition != null) {
transitionController.requestStartTransition(newTransition,
@@ -2031,8 +2072,20 @@ class ActivityStarter {
}
if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
- Slog.e(TAG, "Permission denied: Cannot embed " + r + " to " + mInTaskFragment.getTask()
- + " targetTask= " + targetTask);
+ final StringBuilder errorMsg = new StringBuilder("Permission denied: Cannot embed " + r
+ + " to " + mInTaskFragment.getTask() + ". newTask=" + newTask + ", targetTask= "
+ + targetTask);
+ if (newTask && isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE,
+ LAUNCH_SINGLE_INSTANCE_PER_TASK, LAUNCH_SINGLE_TASK)) {
+ errorMsg.append("\nActivity tries to launch on a new task because the launch mode"
+ + " is " + launchModeToString(mLaunchMode));
+ } else if (newTask && (mLaunchFlags & (FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_NEW_TASK)) != 0) {
+ errorMsg.append("\nActivity tries to launch on a new task because the launch flags"
+ + " contains FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK. "
+ + "mLaunchFlag=" + mLaunchFlags);
+ }
+ Slog.e(TAG, errorMsg.toString());
return START_PERMISSION_DENIED;
}
@@ -2380,6 +2433,7 @@ class ActivityStarter {
mAvoidMoveToFront = false;
mFrozeTaskList = false;
mTransientLaunch = false;
+ mDisplayLockAndOccluded = false;
mVoiceSession = null;
mVoiceInteractor = null;
@@ -2447,6 +2501,11 @@ class ActivityStarter {
}
}
+ if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 && mSourceRecord == null) {
+ // ignore the flag if there is no the sourceRecord
+ mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
+ }
+
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
@@ -2483,6 +2542,16 @@ class ActivityStarter {
mAvoidMoveToFront = true;
}
mTransientLaunch = mOptions.getTransientLaunch();
+ final KeyguardController kc = mSupervisor.getKeyguardController();
+ final int displayId = mPreferredTaskDisplayArea.getDisplayId();
+ mDisplayLockAndOccluded = kc.isKeyguardLocked(displayId)
+ && kc.isDisplayOccluded(displayId);
+ // Recents animation on lock screen, do not resume & move launcher to top.
+ if (mTransientLaunch && mDisplayLockAndOccluded
+ && mService.getTransitionController().isShellTransitionsEnabled()) {
+ mDoResume = false;
+ mAvoidMoveToFront = true;
+ }
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
if (inTaskFragment == null) {
@@ -2750,17 +2819,15 @@ class ActivityStarter {
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, intentTask,
mOptions);
}
- } else {
- // If a launch target indicated, and the matching task is already in the adjacent task
- // of the launch target. Adjust to use the adjacent task as its launch target. So the
- // existing task will be launched into the closer one and won't be reparent redundantly.
- // TODO(b/231541706): Migrate the logic to wm-shell after having proper APIs to help
- // resolve target task without actually starting the activity.
- final Task adjacentTargetTask = mTargetRootTask.getAdjacentTaskFragment() != null
- ? mTargetRootTask.getAdjacentTaskFragment().asTask() : null;
- if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)) {
- mTargetRootTask = adjacentTargetTask;
- }
+ }
+
+ // If the matching task is already in the adjacent task of the launch target. Adjust to use
+ // the adjacent task as its launch target. So the existing task will be launched into the
+ // closer one and won't be reparent redundantly.
+ final Task adjacentTargetTask = mTargetRootTask.getAdjacentTaskFragment() != null
+ ? mTargetRootTask.getAdjacentTaskFragment().asTask() : null;
+ if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)) {
+ mTargetRootTask = adjacentTargetTask;
}
// If the target task is not in the front, then we need to bring it to the front...
@@ -2889,6 +2956,7 @@ class ActivityStarter {
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task;
if (mInTaskFragment != null) {
+ // TODO(b/234351413): remove remaining embedded Task logic.
// mInTaskFragment is created and added to the leaf task by task fragment organizer's
// request. If the task was resolved and different than mInTaskFragment, reparent the
// task to mInTaskFragment for embedding.
@@ -2915,7 +2983,14 @@ class ActivityStarter {
newParent = candidateTf;
}
}
-
+ // Start Activity to the Task if mStartActivity's min dimensions are not satisfied.
+ if (newParent.isEmbedded() && newParent.smallerThanMinDimension(mStartActivity)) {
+ reason += " - MinimumDimensionViolation";
+ mService.mWindowOrganizerController.sendMinimumDimensionViolation(
+ newParent, mStartActivity.getMinDimensions(), mRequest.errorCallbackToken,
+ reason);
+ newParent = task;
+ }
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP);
@@ -3200,6 +3275,11 @@ class ActivityStarter {
return this;
}
+ ActivityStarter setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
+ mRequest.errorCallbackToken = errorCallbackToken;
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.print("mCurrentUser=");
@@ -3234,12 +3314,8 @@ class ActivityStarter {
pw.println(mOptions);
}
pw.print(prefix);
- pw.print("mLaunchSingleTop=");
- pw.print(LAUNCH_SINGLE_TOP == mLaunchMode);
- pw.print(" mLaunchSingleInstance=");
- pw.print(LAUNCH_SINGLE_INSTANCE == mLaunchMode);
- pw.print(" mLaunchSingleTask=");
- pw.println(LAUNCH_SINGLE_TASK == mLaunchMode);
+ pw.print("mLaunchMode=");
+ pw.print(launchModeToString(mLaunchMode));
pw.print(prefix);
pw.print("mLaunchFlags=0x");
pw.print(Integer.toHexString(mLaunchFlags));
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index f75d73b04476..6152676b9be7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -666,9 +666,6 @@ public abstract class ActivityTaskManagerInternal {
public abstract boolean hasSystemAlertWindowPermission(int callingUid, int callingPid,
String callingPackage);
- /** Called when the device is waking up */
- public abstract void notifyWakingUp();
-
/**
* Registers a callback which can intercept activity starts.
* @throws IllegalArgumentException if duplicate ids are provided
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b8162cd3d008..964d6ad91e0c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -64,8 +64,8 @@ import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
import static android.provider.Settings.System.FONT_SCALE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
-import static android.view.WindowManager.TRANSIT_WAKE;
+import static android.view.WindowManager.TRANSIT_PIP;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -73,7 +73,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
-import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.am.ActivityManagerService.dumpStackTraces;
import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER;
@@ -95,6 +94,7 @@ import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen;
import static com.android.server.am.EventLogTags.writeConfigurationChanged;
import static com.android.server.wm.ActivityInterceptorCallback.FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.LAST_ORDERED_ID;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
@@ -116,6 +116,7 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_ONLY;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.Manifest;
@@ -238,6 +239,7 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
@@ -400,6 +402,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** The time at which the previous process was last visible. */
private long mPreviousProcessVisibleTime;
+ /**
+ * It can be true from keyguard-going-away to set-keyguard-shown. And getTopProcessState() will
+ * return {@link ActivityManager#PROCESS_STATE_IMPORTANT_FOREGROUND} to avoid top app from
+ * preempting CPU while keyguard is animating.
+ */
+ private volatile boolean mDemoteTopAppDuringUnlocking;
+
/** List of intents that were used to start the most recent tasks. */
private RecentTasks mRecentTasks;
/** State of external calls telling us if the device is awake or asleep. */
@@ -1789,13 +1798,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public BackNavigationInfo startBackNavigation(boolean requestAnimation) {
+ public BackNavigationInfo startBackNavigation() {
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startBackNavigation()");
if (mBackNavigationController == null) {
return null;
}
- return mBackNavigationController.startBackNavigation(mWindowManager, requestAnimation);
+ return mBackNavigationController.startBackNavigation(mWindowManager);
}
/**
@@ -2830,12 +2839,24 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
keyguardShowing);
mH.sendMessage(msg);
}
+ // Always reset the state regardless of keyguard-showing change, because that means the
+ // unlock is either completed or canceled.
+ if (mDemoteTopAppDuringUnlocking) {
+ mDemoteTopAppDuringUnlocking = false;
+ // The scheduling group of top process was demoted by unlocking, so recompute
+ // to restore its real top priority if possible.
+ if (mTopApp != null) {
+ mTopApp.scheduleUpdateOomAdj();
+ }
+ }
try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown");
mRootWindowContainer.forAllDisplays(displayContent -> {
mKeyguardController.setKeyguardShown(displayContent.getDisplayId(),
keyguardShowing, aodShowing);
});
} finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
Binder.restoreCallingIdentity(ident);
}
}
@@ -2862,6 +2883,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// animation of system UI. Even if AOD is not enabled, it should be no harm.
final WindowProcessController proc;
synchronized (mGlobalLockWithoutBoost) {
+ mDemoteTopAppDuringUnlocking = false;
final WindowState notificationShade = mRootWindowContainer.getDefaultDisplay()
.getDisplayPolicy().getNotificationShade();
proc = notificationShade != null
@@ -3399,8 +3421,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
// Keyguard asked us to clear the home task snapshot before going away, so do that.
- if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) {
+ if ((flags & KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) {
mActivityClientController.invalidateHomeTaskSnapshot(null /* token */);
+ } else if (mKeyguardShown) {
+ // Only set if it is not unlocking to launcher which may also animate.
+ mDemoteTopAppDuringUnlocking = true;
}
mRootWindowContainer.forAllDisplays(displayContent -> {
@@ -3448,10 +3473,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/**
* Puts the given activity in picture in picture mode if possible.
*
+ * @param fromClient true if this comes from a client call (eg. Activity.enterPip).
* @return true if the activity is now in picture-in-picture mode, or false if it could not
* enter picture-in-picture mode.
*/
- boolean enterPictureInPictureMode(@NonNull ActivityRecord r, PictureInPictureParams params) {
+ boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
+ @NonNull PictureInPictureParams params, boolean fromClient) {
// If the activity is already in picture in picture mode, then just return early
if (r.inPinnedWindowingMode()) {
return true;
@@ -3464,6 +3491,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return false;
}
+ // If the app is using legacy-entry (not auto-enter), then we will get a client-request
+ // that was actually a server-request (via pause(userLeaving=true)). This happens when
+ // the app is PAUSING, so detect that case here.
+ boolean originallyFromClient = fromClient
+ && (!r.isState(PAUSING) || params.isAutoEnterEnabled());
+
+ // Create a transition only for this pip entry if it is coming from the app without the
+ // system requesting that the app enter-pip. If the system requested it, that means it
+ // should be part of that transition if possible.
+ final Transition transition =
+ (getTransitionController().isShellTransitionsEnabled() && originallyFromClient)
+ ? new Transition(TRANSIT_PIP, 0 /* flags */,
+ getTransitionController(), mWindowManager.mSyncEngine)
+ : null;
+
final Runnable enterPipRunnable = () -> {
synchronized (mGlobalLock) {
if (r.getParent() == null) {
@@ -3472,7 +3514,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
r.setPictureInPictureParams(params);
mRootWindowContainer.moveActivityToPinnedRootTask(r,
- null /* launchIntoPipHostActivity */, "enterPictureInPictureMode");
+ null /* launchIntoPipHostActivity */, "enterPictureInPictureMode",
+ transition);
final Task task = r.getTask();
// Continue the pausing process after entering pip.
if (task.getPausingActivity() == r) {
@@ -3489,12 +3532,36 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mActivityClientController.dismissKeyguard(r.token, new KeyguardDismissCallback() {
@Override
public void onDismissSucceeded() {
- mH.post(enterPipRunnable);
+ if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Creating Pending Pip-Enter: %s", transition);
+ mWindowManager.mSyncEngine.queueSyncSet(
+ () -> getTransitionController().moveToCollecting(transition),
+ enterPipRunnable);
+ } else {
+ // Move to collecting immediately to "claim" the sync-engine for this
+ // transition.
+ if (transition != null) {
+ getTransitionController().moveToCollecting(transition);
+ }
+ mH.post(enterPipRunnable);
+ }
}
}, null /* message */);
} else {
// Enter picture in picture immediately otherwise
- enterPipRunnable.run();
+ if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Creating Pending Pip-Enter: %s", transition);
+ mWindowManager.mSyncEngine.queueSyncSet(
+ () -> getTransitionController().moveToCollecting(transition),
+ enterPipRunnable);
+ } else {
+ if (transition != null) {
+ getTransitionController().moveToCollecting(transition);
+ }
+ enterPipRunnable.run();
+ }
}
return true;
}
@@ -5595,12 +5662,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public int getTopProcessState() {
+ final int topState = mTopProcessState;
+ if (mDemoteTopAppDuringUnlocking && topState == ActivityManager.PROCESS_STATE_TOP) {
+ // The unlocking UI is more important, so defer the top state of app.
+ return ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ }
if (mRetainPowerModeAndTopProcessState) {
// There is a launching app while device may be sleeping, force the top state so
// the launching process can have top-app scheduling group.
return ActivityManager.PROCESS_STATE_TOP;
}
- return mTopProcessState;
+ return topState;
}
@HotPath(caller = HotPath.PROCESS_CHANGE)
@@ -6624,15 +6696,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void notifyWakingUp() {
- synchronized (mGlobalLock) {
- // Start a transition for waking. This is needed for showWhenLocked activities.
- getTransitionController().requestTransitionIfNeeded(TRANSIT_WAKE, 0 /* flags */,
- null /* trigger */, mRootWindowContainer.getDefaultDisplay());
- }
- }
-
- @Override
public void registerActivityStartInterceptor(
@ActivityInterceptorCallback.OrderedId int id,
ActivityInterceptorCallback callback) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 35f977de8290..bd2ce95a814f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -42,6 +42,7 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
+import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -93,6 +94,7 @@ import android.app.AppOpsManagerInternal;
import android.app.IActivityClientController;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
+import android.app.TaskInfo;
import android.app.WaitResult;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ClientTransaction;
@@ -121,7 +123,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -155,6 +156,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
// TODO: This class has become a dumping ground. Let's
// - Move things relating to the hierarchy to RootWindowContainer
@@ -246,6 +248,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
/** Helper class to abstract out logic for fetching the set of currently running tasks */
private RunningTasks mRunningTasks;
+ /** Helper for {@link Task#fillTaskInfo}. */
+ final TaskInfoHelper mTaskInfoHelper = new TaskInfoHelper();
+
private final ActivityTaskSupervisorHandler mHandler;
final Looper mLooper;
@@ -1316,7 +1321,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
void acquireLaunchWakelock() {
- if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.acquire();
@@ -1389,8 +1394,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
if (mLaunchingActivityWakeLock.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
- if (VALIDATE_WAKE_LOCK_CALLER &&
- Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
@@ -1800,7 +1804,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
if (!mGoingToSleepWakeLock.isHeld()) {
mGoingToSleepWakeLock.acquire();
if (mLaunchingActivityWakeLock.isHeld()) {
- if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
@@ -2461,8 +2465,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
case LAUNCH_TIMEOUT_MSG: {
if (mLaunchingActivityWakeLock.isHeld()) {
Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
- if (VALIDATE_WAKE_LOCK_CALLER
- && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
@@ -2623,6 +2626,41 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
/**
+ * Fills the info that needs to iterate all activities of task, such as the number of
+ * non-finishing activities and collecting launch cookies.
+ */
+ static class TaskInfoHelper implements Consumer<ActivityRecord> {
+ private TaskInfo mInfo;
+ private ActivityRecord mTopRunning;
+
+ ActivityRecord fillAndReturnTop(Task task, TaskInfo info) {
+ info.numActivities = 0;
+ info.baseActivity = null;
+ mInfo = info;
+ task.forAllActivities(this);
+ final ActivityRecord top = mTopRunning;
+ mTopRunning = null;
+ mInfo = null;
+ return top;
+ }
+
+ @Override
+ public void accept(ActivityRecord r) {
+ if (r.finishing) {
+ return;
+ }
+ if (r.mLaunchCookie != null) {
+ mInfo.addLaunchCookie(r.mLaunchCookie);
+ }
+ mInfo.numActivities++;
+ mInfo.baseActivity = r.mActivityComponent;
+ if (mTopRunning == null) {
+ mTopRunning = r;
+ }
+ }
+ }
+
+ /**
* Internal container to store a match qualifier alongside a WaitResult.
*/
private static class WaitInfo {
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 6befefda8a12..b23f50154257 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -256,7 +256,7 @@ class AnrController {
Slog.i(TAG_WM, "Pre-dump for unresponsive");
final ArrayList<Integer> firstPids = new ArrayList<>(1);
- firstPids.add(ActivityManagerService.MY_PID);
+ firstPids.add(WindowManagerService.MY_PID);
ArrayList<Integer> nativePids = null;
final int[] pids = shouldDumpSf[0]
? Process.getPidsForCommands(new String[] { "/system/bin/surfaceflinger" })
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 5410dd8508f1..66ac99e3651d 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -34,6 +34,8 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
@@ -64,6 +66,9 @@ import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnte
import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
@@ -282,13 +287,6 @@ public class AppTransition implements Dump {
fetchAppTransitionSpecsFromFuture();
}
- void abort() {
- if (mRemoteAnimationController != null) {
- mRemoteAnimationController.cancelAnimation("aborted");
- }
- clear();
- }
-
boolean isRunning() {
return mAppTransitionState == APP_STATE_RUNNING;
}
@@ -645,9 +643,15 @@ public class AppTransition implements Dump {
@Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
boolean freeform, WindowContainer container) {
- if (mNextAppTransitionOverrideRequested
- && (container.canCustomizeAppTransition() || mOverrideTaskTransition)) {
- mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+ final boolean canCustomizeAppTransition = container.canCustomizeAppTransition();
+
+ if (mNextAppTransitionOverrideRequested) {
+ if (canCustomizeAppTransition || mOverrideTaskTransition) {
+ mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+ } else {
+ ProtoLog.e(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: "
+ + " override requested, but it is prohibited by policy.");
+ }
}
Animation a;
@@ -835,14 +839,26 @@ public class AppTransition implements Dump {
? WindowAnimation_activityCloseEnterAnimation
: WindowAnimation_activityCloseExitAnimation;
break;
+ case TRANSIT_OLD_DREAM_ACTIVITY_OPEN:
+ animAttr = enter
+ ? WindowAnimation_dreamActivityOpenEnterAnimation
+ : WindowAnimation_dreamActivityOpenExitAnimation;
+ break;
+ case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE:
+ animAttr = enter
+ ? 0
+ : WindowAnimation_dreamActivityCloseExitAnimation;
+ break;
}
- a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
+ a = animAttr == 0 ? null : (canCustomizeAppTransition
+ ? loadAnimationAttr(lp, animAttr, transit)
+ : mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit));
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
- + "Callers=%s",
+ + " canCustomizeAppTransition=%b Callers=%s",
a, animAttr, appTransitionOldToString(transit), enter,
- Debug.getCallers(3));
+ canCustomizeAppTransition, Debug.getCallers(3));
}
setAppTransitionFinishedCallbackIfNeeded(a);
@@ -1157,6 +1173,12 @@ public class AppTransition implements Dump {
case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: {
return "TRANSIT_OLD_TASK_FRAGMENT_CHANGE";
}
+ case TRANSIT_OLD_DREAM_ACTIVITY_OPEN: {
+ return "TRANSIT_OLD_DREAM_ACTIVITY_OPEN";
+ }
+ case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE: {
+ return "TRANSIT_OLD_DREAM_ACTIVITY_CLOSE";
+ }
default: {
return "<UNKNOWN: " + transition + ">";
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 140ac333e3af..abb3f3af66fb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
@@ -32,6 +33,8 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
@@ -98,8 +101,8 @@ import com.android.internal.protolog.common.ProtoLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -340,6 +343,9 @@ public class AppTransitionController {
ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
@Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
+ final ActivityRecord topOpeningApp = getTopApp(openingApps, false /* ignoreHidden */);
+ final ActivityRecord topClosingApp = getTopApp(closingApps, true /* ignoreHidden */);
+
// Determine if closing and opening app token sets are wallpaper targets, in which case
// special animations are needed.
final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps)
@@ -347,7 +353,7 @@ public class AppTransitionController {
final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps)
&& wallpaperTarget != null;
- // Keyguard transit has highest priority.
+ // Keyguard transit has high priority.
switch (appTransition.getKeyguardTransition()) {
case TRANSIT_KEYGUARD_GOING_AWAY:
return openingAppHasWallpaper ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
@@ -362,6 +368,15 @@ public class AppTransitionController {
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
+ // Determine whether the top opening and closing activity is a dream activity. If so, this
+ // has higher priority than others except keyguard transit.
+ if (topOpeningApp != null && topOpeningApp.getActivityType() == ACTIVITY_TYPE_DREAM) {
+ return TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
+ } else if (topClosingApp != null
+ && topClosingApp.getActivityType() == ACTIVITY_TYPE_DREAM) {
+ return TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
+ }
+
// This is not keyguard transition and one of the app has request to skip app transition.
if (skipAppTransitionAnimation) {
return WindowManager.TRANSIT_OLD_UNSET;
@@ -425,11 +440,6 @@ public class AppTransitionController {
}
}
- final ActivityRecord topOpeningApp = getTopApp(openingApps,
- false /* ignoreHidden */);
- final ActivityRecord topClosingApp = getTopApp(closingApps,
- true /* ignoreHidden */);
-
if (closingAppHasWallpaper && openingAppHasWallpaper) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
switch (firstTransit) {
@@ -879,7 +889,7 @@ public class AppTransitionController {
boolean visible) {
// The candidates of animation targets, which might be able to promote to higher level.
- final LinkedList<WindowContainer> candidates = new LinkedList<>();
+ final ArrayDeque<WindowContainer> candidates = new ArrayDeque<>();
final ArraySet<ActivityRecord> apps = visible ? openingApps : closingApps;
for (int i = 0; i < apps.size(); ++i) {
final ActivityRecord app = apps.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 61deb59084c5..b519dadb2031 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -144,8 +144,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
// Legacy animation doesn't need to wait for the start transaction.
if (mTransitionOp == OP_LEGACY) {
mIsStartTransactionCommitted = true;
- } else if (displayContent.mTransitionController.useShellTransitionsRotation()
- || displayContent.mTransitionController.isCollecting(displayContent)) {
+ } else if (displayContent.mTransitionController.isCollecting(displayContent)) {
keepAppearanceInPreviousRotation();
}
}
@@ -214,10 +213,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume
private void finishOp(WindowToken windowToken) {
final Operation op = mTargetWindowTokens.remove(windowToken);
if (op == null) return;
- if (op.mCapturedDrawTransaction != null) {
+ if (op.mDrawTransaction != null) {
// Unblock the window to show its latest content.
- mDisplayContent.getPendingTransaction().merge(op.mCapturedDrawTransaction);
- op.mCapturedDrawTransaction = null;
+ mDisplayContent.getPendingTransaction().merge(op.mDrawTransaction);
+ op.mDrawTransaction = null;
if (DEBUG) Slog.d(TAG, "finishOp merge transaction " + windowToken.getTopChild());
}
if (op.mAction == Operation.ACTION_FADE) {
@@ -351,14 +350,34 @@ class AsyncRotationController extends FadeAnimationController implements Consume
}
/**
- * Whether the insets animation leash should use previous position when running fade out
- * animation in rotated display.
+ * Whether the insets animation leash should use previous position when running fade animation
+ * or seamless transformation in a rotated display.
*/
boolean shouldFreezeInsetsPosition(WindowState w) {
return mTransitionOp == OP_APP_SWITCH && w.mTransitionController.inTransition()
&& isTargetToken(w.mToken);
}
+ /**
+ * Returns the transaction which will be applied after the window redraws in new rotation.
+ * This is used to update the position of insets animation leash synchronously.
+ */
+ SurfaceControl.Transaction getDrawTransaction(WindowToken token) {
+ if (mTransitionOp == OP_LEGACY) {
+ // Legacy transition uses startSeamlessRotation and finishSeamlessRotation of
+ // InsetsSourceProvider.
+ return null;
+ }
+ final Operation op = mTargetWindowTokens.get(token);
+ if (op != null) {
+ if (op.mDrawTransaction == null) {
+ op.mDrawTransaction = new SurfaceControl.Transaction();
+ }
+ return op.mDrawTransaction;
+ }
+ return null;
+ }
+
void setOnShowRunnable(Runnable onShowRunnable) {
mOnShowRunnable = onShowRunnable;
}
@@ -463,10 +482,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume
final boolean keepUntilStartTransaction =
!mIsStartTransactionCommitted && op.mAction == Operation.ACTION_SEAMLESS;
if (!keepUntilTransitionFinish && !keepUntilStartTransaction) return false;
- if (op.mCapturedDrawTransaction == null) {
- op.mCapturedDrawTransaction = postDrawTransaction;
+ if (op.mDrawTransaction == null) {
+ op.mDrawTransaction = postDrawTransaction;
} else {
- op.mCapturedDrawTransaction.merge(postDrawTransaction);
+ op.mDrawTransaction.merge(postDrawTransaction);
}
if (DEBUG) Slog.d(TAG, "Capture draw transaction " + w);
return true;
@@ -512,7 +531,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
* the start transaction of transition, so there won't be a flickering such as the window
* has redrawn during fading out.
*/
- SurfaceControl.Transaction mCapturedDrawTransaction;
+ SurfaceControl.Transaction mDrawTransaction;
Operation(@Action int action) {
mAction = action;
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 46ce43335f01..9a94a4f54b61 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -236,12 +236,18 @@ class BLASTSyncEngine {
private void onTimeout() {
if (!mActiveSyncs.contains(mSyncId)) return;
+ boolean allFinished = true;
for (int i = mRootMembers.size() - 1; i >= 0; --i) {
final WindowContainer<?> wc = mRootMembers.valueAt(i);
if (!wc.isSyncFinished()) {
+ allFinished = false;
Slog.i(TAG, "Unfinished container: " + wc);
}
}
+ if (allFinished && !mReady) {
+ Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see "
+ + "this, please file a bug.");
+ }
finishNow();
}
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d07cc68af890..dac72d820251 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -61,6 +61,10 @@ class BackNavigationController {
return SystemProperties.getInt("persist.wm.debug.predictive_back_screenshot", 0) != 0;
}
+ private static boolean isAnimationEnabled() {
+ return SystemProperties.getInt("persist.wm.debug.predictive_back_anim", 0) != 0;
+ }
+
/**
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
* back gesture animation.
@@ -70,21 +74,20 @@ class BackNavigationController {
* fallback on dispatching the key event.
*/
@Nullable
- BackNavigationInfo startBackNavigation(@NonNull WindowManagerService wmService,
- boolean requestAnimation) {
- return startBackNavigation(wmService, null, requestAnimation);
+ BackNavigationInfo startBackNavigation(@NonNull WindowManagerService wmService) {
+ return startBackNavigation(wmService, null);
}
/**
* @param tx, a transaction to be used for the attaching the animation leash.
* This is used in tests. If null, the object will be initialized with a new {@link
* SurfaceControl.Transaction}
- * @see #startBackNavigation(WindowManagerService, boolean)
+ * @see #startBackNavigation(WindowManagerService)
*/
@VisibleForTesting
@Nullable
BackNavigationInfo startBackNavigation(WindowManagerService wmService,
- @Nullable SurfaceControl.Transaction tx, boolean requestAnimation) {
+ @Nullable SurfaceControl.Transaction tx) {
if (tx == null) {
tx = new SurfaceControl.Transaction();
@@ -292,7 +295,7 @@ class BackNavigationController {
}
// Special handling for back to home animation
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()
&& prevTask != null) {
currentTask.mBackGestureStarted = true;
// Make launcher show from behind by marking its top activity as visible and
@@ -347,7 +350,7 @@ class BackNavigationController {
Task finalTask = currentTask;
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
result, finalRemovedWindowContainer, finalBackType, finalTask,
- finalprevActivity, requestAnimation));
+ finalprevActivity));
infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
}
@@ -381,14 +384,14 @@ class BackNavigationController {
private void onBackNavigationDone(
Bundle result, WindowContainer<?> windowContainer, int backType,
- Task task, ActivityRecord prevActivity, boolean requestAnimation) {
+ Task task, ActivityRecord prevActivity) {
SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
boolean triggerBack = result != null && result.getBoolean(
BackNavigationInfo.KEY_TRIGGER_BACK);
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "task=%s, prevActivity=%s", backType, task, prevActivity);
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation) {
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
if (triggerBack) {
if (surfaceControl != null && surfaceControl.isValid()) {
// When going back to home, hide the task surface before it is re-parented to
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index fcdf175cb809..0c6cea82e00c 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -486,14 +486,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return WindowConfiguration.inMultiWindowMode(windowingMode);
}
- /**
- * Returns true if this container supports split-screen multi-window and can be put in
- * split-screen based on its current state.
- */
- public boolean supportsSplitScreenWindowingMode() {
- return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
- }
-
public boolean inPinnedWindowingMode() {
return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a059ac613dde..9137279dc8fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -558,7 +558,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final FixedRotationTransitionListener mFixedRotationTransitionListener =
new FixedRotationTransitionListener();
- private PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
+ private final PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
+ final RemoteDisplayChangeController mRemoteDisplayChangeController;
/** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
final ArrayList<WindowState> mWinAddedSinceNullFocus = new ArrayList<>();
@@ -1054,6 +1055,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
mDisplaySwitchTransitionLauncher = new PhysicalDisplaySwitchTransitionLauncher(this,
mTransitionController);
+ mRemoteDisplayChangeController = new RemoteDisplayChangeController(mWmService, mDisplayId);
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
"PointerEventDispatcher" + mDisplayId, mDisplayId);
@@ -1435,7 +1437,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!isReady()) {
return;
}
- if (mDisplayRotation.isWaitingForRemoteRotation()) {
+ if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
return;
}
@@ -1535,8 +1537,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
config = new Configuration();
computeScreenConfiguration(config);
} else if (!(mTransitionController.isCollecting(this)
- // If waiting for a remote rotation, don't prematurely update configuration.
- || mDisplayRotation.isWaitingForRemoteRotation())) {
+ // If waiting for a remote display change, don't prematurely update configuration.
+ || mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange())) {
// No obvious action we need to take, but if our current state mismatches the
// activity manager's, update it, disregarding font scale, which should remain set
// to the value of the previous configuration.
@@ -1583,8 +1585,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
- // Currently there is no use case from non-activity.
- if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
+ // The orientation source may not be the top if it uses SCREEN_ORIENTATION_BEHIND.
+ final ActivityRecord topCandidate = !r.mVisibleRequested ? topRunningActivity() : r;
+ if (handleTopActivityLaunchingInDifferentOrientation(
+ topCandidate, r, true /* checkOpening */)) {
// Display orientation should be deferred until the top fixed rotation is finished.
return false;
}
@@ -1596,12 +1600,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
boolean isSyncFinished() {
// Do not consider children because if they are requested to be synced, they should be
// added to sync group explicitly.
- return !mDisplayRotation.isWaitingForRemoteRotation();
+ return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange();
}
/**
* Returns a valid rotation if the activity can use different orientation than the display.
- * Otherwise {@link #ROTATION_UNDEFINED}.
+ * Otherwise {@link android.app.WindowConfiguration#ROTATION_UNDEFINED}.
*/
@Rotation
int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
@@ -1611,6 +1615,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return ROTATION_UNDEFINED;
}
+ if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ final ActivityRecord nextCandidate = getActivity(
+ a -> a.mOrientation != SCREEN_ORIENTATION_UNSET
+ && a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
+ r, false /* includeBoundary */, true /* traverseTopToBottom */);
+ if (nextCandidate != null) {
+ r = nextCandidate;
+ }
+ }
if (r.inMultiWindowMode() || r.getRequestedConfigurationOrientation(true /* forDisplay */)
== getConfiguration().orientation) {
return ROTATION_UNDEFINED;
@@ -1624,18 +1637,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return rotation;
}
+ boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
+ boolean checkOpening) {
+ return handleTopActivityLaunchingInDifferentOrientation(r, r, checkOpening);
+ }
+
/**
* We need to keep display rotation fixed for a while when the activity in different orientation
* is launching until the launch animation is done to avoid showing the previous activity
* inadvertently in a wrong orientation.
*
* @param r The launching activity which may change display orientation.
+ * @param orientationSrc It may be different from {@param r} if the launching activity uses
+ * "behind" orientation.
* @param checkOpening Whether to check if the activity is animating by transition. Set to
* {@code true} if the caller is not sure whether the activity is launching.
* @return {@code true} if the fixed rotation is started.
*/
- boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
- boolean checkOpening) {
+ private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
+ @NonNull ActivityRecord orientationSrc, boolean checkOpening) {
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return false;
}
@@ -1684,7 +1704,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// animation is not running (it may be swiping to home).
return false;
}
- final int rotation = rotationForActivityInDifferentOrientation(r);
+ final int rotation = rotationForActivityInDifferentOrientation(orientationSrc);
if (rotation == ROTATION_UNDEFINED) {
// The display rotation won't be changed by current top activity. The client side
// adjustments of previous rotated activity should be cleared earlier. Otherwise if
@@ -1813,8 +1833,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
sendNewConfiguration();
return;
}
- if (mDisplayRotation.isWaitingForRemoteRotation()) {
- // There is pending rotation change to apply.
+ if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
+ // There is pending display change to apply.
return;
}
// The orientation of display is not changed.
@@ -2015,7 +2035,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
ProtoLog.v(WM_DEBUG_ORIENTATION, "Set mOrientationChanging of %s", w);
w.setOrientationChanging(true);
}
- w.mReportOrientationChanged = true;
}, true /* traverseTopToBottom */);
for (int i = mWmService.mRotationWatchers.size() - 1; i >= 0; i--) {
@@ -2205,9 +2224,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final float density = mDisplayMetrics.density;
outConfig.screenWidthDp = (int) (mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation,
- uiMode, displayCutout) / density);
+ uiMode, displayCutout) / density + 0.5f);
outConfig.screenHeightDp = (int) (mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation,
- uiMode, displayCutout) / density);
+ uiMode, displayCutout) / density + 0.5f);
outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
@@ -2390,7 +2409,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode);
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode);
- outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
+ outConfig.smallestScreenWidthDp =
+ (int) (displayInfo.smallestNominalAppWidth / density + 0.5f);
outConfig.screenLayout = sl;
}
@@ -2412,8 +2432,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
longSize = shortSize;
shortSize = tmp;
}
- longSize = (int)(longSize/density);
- shortSize = (int)(shortSize/density);
+ longSize = (int) (longSize / density + 0.5f);
+ shortSize = (int) (shortSize / density + 0.5f);
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
}
@@ -2758,6 +2778,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private void updateBaseDisplayMetricsIfNeeded() {
// Get real display metrics without overrides from WM.
mWmService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo);
+ final int currentRotation = getRotation();
final int orientation = mDisplayInfo.rotation;
final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
@@ -2818,7 +2839,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
reconfigureDisplayLocked();
if (physicalDisplayChanged) {
- mDisplaySwitchTransitionLauncher.onDisplayUpdated();
+ mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(),
+ getDisplayAreaInfo());
}
}
}
@@ -4527,8 +4549,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
boolean wallpaperEnabled = mWmService.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableWallpaperService)
&& mWmService.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_checkWallpaperAtBoot)
- && !mWmService.mOnlyCore;
+ com.android.internal.R.bool.config_checkWallpaperAtBoot);
final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS);
final boolean haveApp = drawnWindowTypes.get(TYPE_BASE_APPLICATION);
@@ -5321,11 +5342,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- void cancelAppTransition() {
- if (!mAppTransition.isTransitionSet() || mAppTransition.isRunning()) return;
- mAppTransition.abort();
- }
-
/**
* Update pendingLayoutChanges after app transition has finished.
*/
@@ -5392,6 +5408,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mOverlayLayer;
}
+ SurfaceControl[] findRoundedCornerOverlays() {
+ List<SurfaceControl> roundedCornerOverlays = new ArrayList<>();
+ for (WindowToken token : mTokenMap.values()) {
+ if (token.mRoundedCornerOverlay) {
+ roundedCornerOverlays.add(token.mSurfaceControl);
+ }
+ }
+ return roundedCornerOverlays.toArray(new SurfaceControl[0]);
+ }
+
/**
* Updates the display's system gesture exclusion.
*
@@ -6081,7 +6107,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
notifyClients);
});
- if (mTransitionController.isCollecting()
+ if (mTransitionController.useShellTransitionsRotation()
+ && mTransitionController.isCollecting()
&& mWallpaperController.getWallpaperTarget() != null) {
// Also update wallpapers so that their requestedVisibility immediately reflects
// the changes to activity visibility.
@@ -6250,7 +6277,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/**
* Sets if Display APIs should be sandboxed to the activity window bounds.
*/
- @VisibleForTesting
void setSandboxDisplayApis(boolean sandboxDisplayApis) {
mSandboxDisplayApis = sandboxDisplayApis;
}
diff --git a/services/core/java/com/android/server/wm/DisplayHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java
index 64a57588113c..543d4ad6b507 100644
--- a/services/core/java/com/android/server/wm/DisplayHashController.java
+++ b/services/core/java/com/android/server/wm/DisplayHashController.java
@@ -369,9 +369,6 @@ public class DisplayHashController {
if (mServiceConnection == null) {
if (DEBUG) Slog.v(TAG, "creating connection");
- // Create the connection
- mServiceConnection = new DisplayHashingServiceConnection();
-
final ComponentName component = getServiceComponentName();
if (DEBUG) Slog.v(TAG, "binding to: " + component);
if (component != null) {
@@ -379,6 +376,8 @@ public class DisplayHashController {
intent.setComponent(component);
final long token = Binder.clearCallingIdentity();
try {
+ // Create the connection
+ mServiceConnection = new DisplayHashingServiceConnection();
mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
if (DEBUG) Slog.v(TAG, "bound");
} finally {
@@ -387,7 +386,9 @@ public class DisplayHashController {
}
}
- mServiceConnection.runCommandLocked(command);
+ if (mServiceConnection != null) {
+ mServiceConnection.runCommandLocked(command);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 7e91989a9105..daeba967ec76 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -61,6 +61,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_WAKE;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
@@ -778,7 +779,22 @@ public class DisplayPolicy {
}
public void setAwake(boolean awake) {
+ if (awake == mAwake) {
+ return;
+ }
mAwake = awake;
+ synchronized (mService.mGlobalLock) {
+ if (!mDisplayContent.isDefaultDisplay) {
+ return;
+ }
+ if (mAwake) {
+ // Start a transition for waking. This is needed for showWhenLocked activities.
+ mDisplayContent.mTransitionController.requestTransitionIfNeeded(TRANSIT_WAKE,
+ 0 /* flags */, null /* trigger */, mDisplayContent);
+ }
+ mService.mAtmService.mKeyguardController.updateDeferWakeTransition(
+ mAwake /* waiting */);
+ }
}
public boolean isAwake() {
@@ -1231,29 +1247,6 @@ public class DisplayPolicy {
}
inOutFrame.inset(win.mGivenContentInsets);
} : null, imeFrameProvider);
- if (mNavigationBar == null && (insetsType == ITYPE_NAVIGATION_BAR
- || insetsType == ITYPE_EXTRA_NAVIGATION_BAR)) {
- mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
- (displayFrames, windowState, inOutFrame) -> {
- final int leftSafeInset =
- Math.max(displayFrames.mDisplayCutoutSafe.left,0);
- inOutFrame.left = 0;
- inOutFrame.top = 0;
- inOutFrame.bottom = displayFrames.mDisplayHeight;
- inOutFrame.right =
- leftSafeInset + mLeftGestureInset;
- });
- mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
- (displayFrames, windowState, inOutFrame) -> {
- final int rightSafeInset =
- Math.min(displayFrames.mDisplayCutoutSafe.right,
- displayFrames.mUnrestricted.right);
- inOutFrame.left = rightSafeInset - mRightGestureInset;
- inOutFrame.top = 0;
- inOutFrame.bottom = displayFrames.mDisplayHeight;
- inOutFrame.right = displayFrames.mDisplayWidth;
- });
- }
mInsetsSourceWindowsExceptIme.add(win);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 03e1429f1bf1..a78d25f4e21a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -51,14 +51,12 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.power.Boost;
import android.os.Handler;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import android.view.IDisplayWindowRotationCallback;
import android.view.IWindowManager;
import android.view.Surface;
import android.window.TransitionRequestInfo;
@@ -67,7 +65,6 @@ import android.window.WindowContainerTransaction;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
@@ -211,31 +208,6 @@ public class DisplayRotation {
private boolean mDemoHdmiRotationLock;
private boolean mDemoRotationLock;
- private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
-
- private boolean mIsWaitingForRemoteRotation = false;
-
- private final Runnable mDisplayRotationHandlerTimeout =
- new Runnable() {
- @Override
- public void run() {
- continueRotation(mRotation, null /* transaction */);
- }
- };
-
- private final IDisplayWindowRotationCallback mRemoteRotationCallback =
- new IDisplayWindowRotationCallback.Stub() {
- @Override
- public void continueRotateDisplay(int targetRotation,
- WindowContainerTransaction t) {
- synchronized (mService.getWindowManagerLock()) {
- mService.mH.sendMessage(PooledLambda.obtainMessage(
- DisplayRotation::continueRotation, DisplayRotation.this,
- targetRotation, t));
- }
- }
- };
-
DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
this(service, displayContent, displayContent.getDisplayPolicy(),
service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
@@ -511,6 +483,7 @@ public class DisplayRotation {
final TransitionRequestInfo.DisplayChange change = wasCollecting ? null
: new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(),
oldRotation, mRotation);
+
mDisplayContent.requestChangeTransitionIfNeeded(
ActivityInfo.CONFIG_WINDOW_CONFIGURATION, change);
if (wasCollecting) {
@@ -554,61 +527,39 @@ public class DisplayRotation {
return null;
}
- /**
- * A Remote rotation is when we are waiting for some registered (remote)
- * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
- * to perform in sync with the rotation.
- */
- boolean isWaitingForRemoteRotation() {
- return mIsWaitingForRemoteRotation;
- }
-
private void startRemoteRotation(int fromRotation, int toRotation) {
- if (mService.mDisplayRotationController == null) {
- return;
- }
- mIsWaitingForRemoteRotation = true;
- try {
- mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
- fromRotation, toRotation, mRemoteRotationCallback);
- mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
- mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
- } catch (RemoteException e) {
- mIsWaitingForRemoteRotation = false;
- return;
- }
+ mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
+ fromRotation, toRotation, null /* newDisplayAreaInfo */,
+ (transaction) -> continueRotation(toRotation, transaction)
+ );
}
private void continueRotation(int targetRotation, WindowContainerTransaction t) {
- synchronized (mService.mGlobalLock) {
- if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
- // Drop it, this is either coming from an outdated remote rotation; or, we've
- // already moved on.
- return;
- }
- mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
- mIsWaitingForRemoteRotation = false;
+ if (targetRotation != mRotation) {
+ // Drop it, this is either coming from an outdated remote rotation; or, we've
+ // already moved on.
+ return;
+ }
- if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
- if (!mDisplayContent.mTransitionController.isCollecting()) {
- throw new IllegalStateException("Trying to rotate outside a transition");
- }
- mDisplayContent.mTransitionController.collect(mDisplayContent);
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
- // handling is synchronized.
- mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
- null /* use collecting transition */);
+ if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
+ if (!mDisplayContent.mTransitionController.isCollecting()) {
+ throw new IllegalStateException("Trying to rotate outside a transition");
}
- mService.mAtmService.deferWindowLayout();
- try {
- mDisplayContent.sendNewConfiguration();
- if (t != null) {
- mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
- }
- } finally {
- mService.mAtmService.continueWindowLayout();
+ mDisplayContent.mTransitionController.collect(mDisplayContent);
+ // Go through all tasks and collect them before the rotation
+ // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
+ // handling is synchronized.
+ mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
+ null /* use collecting transition */);
+ }
+ mService.mAtmService.deferWindowLayout();
+ try {
+ mDisplayContent.sendNewConfiguration();
+ if (t != null) {
+ mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
}
+ } finally {
+ mService.mAtmService.continueWindowLayout();
}
}
@@ -1571,8 +1522,8 @@ public class DisplayRotation {
}
@Override
- public boolean isKeyguardLocked() {
- return mService.isKeyguardLocked();
+ public boolean isKeyguardShowingAndNotOccluded() {
+ return mService.isKeyguardShowingAndNotOccluded();
}
@Override
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c47d778c60bc..73f0d31e1944 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -31,6 +31,8 @@ import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DR
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.MY_PID;
+import static com.android.server.wm.WindowManagerService.MY_UID;
import android.animation.Animator;
import android.animation.PropertyValuesHolder;
@@ -45,7 +47,6 @@ import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -207,8 +208,6 @@ class DragState {
// Send drag end broadcast if drag start has been sent.
if (mDragInProgress) {
- final int myPid = Process.myPid();
-
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
}
@@ -236,7 +235,7 @@ class DragState {
}
// if the current window is in the same process,
// the dispatch has already recycled the event
- if (myPid != ws.mSession.mPid) {
+ if (MY_PID != ws.mSession.mPid) {
event.recycle();
}
}
@@ -320,7 +319,6 @@ class DragState {
mData.fixUris(mSourceUserId);
}
}
- final int myPid = Process.myPid();
final IBinder clientToken = touchedWin.mClient.asBinder();
final DragEvent event = obtainDragEvent(DragEvent.ACTION_DROP, x, y,
mData, targetInterceptsGlobalDrag(touchedWin),
@@ -336,7 +334,7 @@ class DragState {
endDragLocked();
return false;
} finally {
- if (myPid != touchedWin.mSession.mPid) {
+ if (MY_PID != touchedWin.mSession.mPid) {
event.recycle();
}
}
@@ -364,8 +362,8 @@ class DragState {
mDragWindowHandle.token = mClientChannel.getToken();
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.ownerPid = Process.myPid();
- mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.ownerPid = MY_PID;
+ mDragWindowHandle.ownerUid = MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
// Keep the default behavior of this window to be focusable, which allows the system
@@ -477,7 +475,7 @@ class DragState {
Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
} finally {
// if the callee was local, the dispatch has already recycled the event
- if (Process.myPid() != newWin.mSession.mPid) {
+ if (MY_PID != newWin.mSession.mPid) {
event.recycle();
}
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 59be3e05f2c0..39622c1c5aaf 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -23,7 +23,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.view.InputApplicationHandle;
@@ -72,8 +71,8 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.ownerPid = Process.myPid();
- mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mWindowHandle.ownerUid = WindowManagerService.MY_UID;
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 33cdd2e98113..b7ddbd070460 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -265,7 +265,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
.setContainerLayer()
.setName(name)
.setCallsite("createSurfaceForGestureMonitor")
- .setParent(dc.getSurfaceControl())
+ .setParent(dc.getOverlayLayer())
.build();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 7e06b8823260..fd183b2b0e21 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -24,7 +24,6 @@ import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
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.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -82,7 +81,6 @@ final class InputMonitor {
private boolean mUpdateInputWindowsPending;
private boolean mUpdateInputWindowsImmediately;
- private boolean mDisableWallpaperTouchEvents;
private final Region mTmpRegion = new Region();
private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
@@ -272,7 +270,7 @@ final class InputMonitor {
final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
&& !mService.mPolicy.isKeyguardShowing()
- && !mDisableWallpaperTouchEvents;
+ && w.mAttrs.areWallpaperTouchEventsEnabled();
inputWindowHandle.setHasWallpaper(hasWallpaper);
// Surface insets are hardcoded to be the same in all directions
@@ -527,7 +525,6 @@ final class InputMonitor {
mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
- mDisableWallpaperTouchEvents = false;
mInDrag = inDrag;
resetInputConsumers(mInputTransaction);
@@ -572,8 +569,6 @@ final class InputMonitor {
return;
}
- final int privateFlags = w.mAttrs.privateFlags;
-
// This only works for legacy transitions.
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
@@ -618,10 +613,6 @@ final class InputMonitor {
}
}
- if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
- mDisableWallpaperTouchEvents = true;
- }
-
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 358e93d89f64..178e299d317a 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -290,7 +290,22 @@ abstract class InsetsSourceProvider {
&& windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) {
windowState.applyWithNextDraw(mSetLeashPositionConsumer);
} else {
- mSetLeashPositionConsumer.accept(mWindowContainer.getSyncTransaction());
+ Transaction t = mWindowContainer.getSyncTransaction();
+ if (windowState != null) {
+ // Make the buffer, token transformation, and leash position to be updated
+ // together when the window is drawn for new rotation. Otherwise the window
+ // may be outside the screen by the inconsistent orientations.
+ final AsyncRotationController rotationController =
+ mDisplayContent.getAsyncRotationController();
+ if (rotationController != null) {
+ final Transaction drawT =
+ rotationController.getDrawTransaction(windowState.mToken);
+ if (drawT != null) {
+ t = drawT;
+ }
+ }
+ }
+ mSetLeashPositionConsumer.accept(t);
}
}
if (mServerVisible && !mLastSourceFrame.equals(mSource.getFrame())) {
@@ -310,17 +325,15 @@ abstract class InsetsSourceProvider {
}
private Point getWindowFrameSurfacePosition() {
- WindowState win = mWindowContainer.asWindowState();
- if (mControl != null) {
- final AsyncRotationController controller =
- win.mDisplayContent.getAsyncRotationController();
+ final WindowState win = mWindowContainer.asWindowState();
+ if (win != null && mControl != null) {
+ final AsyncRotationController controller = mDisplayContent.getAsyncRotationController();
if (controller != null && controller.shouldFreezeInsetsPosition(win)) {
- // Use previous position because the fade-out animation runs in old rotation.
+ // Use previous position because the window still shows with old rotation.
return mControl.getSurfacePosition();
}
}
- final Rect frame = mWindowContainer.asWindowState() != null
- ? mWindowContainer.asWindowState().getFrame() : mWindowContainer.getBounds();
+ final Rect frame = win != null ? win.getFrame() : mWindowContainer.getBounds();
final Point position = new Point();
mWindowContainer.transformFrameToSurfacePosition(frame.left, frame.top, position);
return position;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index f36dbfa2316e..4d971a9f52da 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -72,6 +72,8 @@ class KeyguardController {
static final String KEYGUARD_SLEEP_TOKEN_TAG = "keyguard";
+ private static final int DEFER_WAKE_TRANSITION_TIMEOUT_MS = 5000;
+
private final ActivityTaskSupervisor mTaskSupervisor;
private WindowManagerService mWindowManager;
@@ -79,7 +81,7 @@ class KeyguardController {
private final ActivityTaskManagerService mService;
private RootWindowContainer mRootWindowContainer;
private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
-
+ private boolean mWaitingForWakeTransition;
KeyguardController(ActivityTaskManagerService service,
ActivityTaskSupervisor taskSupervisor) {
@@ -171,6 +173,9 @@ class KeyguardController {
// Do not reset keyguardChanged status if this is aodChanged.
final boolean keyguardChanged = (keyguardShowing != state.mKeyguardShowing)
|| (state.mKeyguardGoingAway && keyguardShowing && !aodChanged);
+ if (aodChanged && !aodShowing) {
+ updateDeferWakeTransition(false /* waiting */);
+ }
if (!keyguardChanged && !aodChanged) {
setWakeTransitionReady();
return;
@@ -199,10 +204,6 @@ class KeyguardController {
state.mKeyguardShowing = keyguardShowing;
state.mAodShowing = aodShowing;
- if (aodChanged) {
- // Ensure the new state takes effect.
- mWindowManager.mWindowPlacerLocked.performSurfacePlacement();
- }
if (keyguardChanged) {
// Irrelevant to AOD.
@@ -220,6 +221,10 @@ class KeyguardController {
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
setWakeTransitionReady();
+ if (aodChanged) {
+ // Ensure the new state takes effect.
+ mWindowManager.mWindowPlacerLocked.performSurfacePlacement();
+ }
}
private void setWakeTransitionReady() {
@@ -526,6 +531,33 @@ class KeyguardController {
}
}
+ private final Runnable mResetWaitTransition = () -> {
+ synchronized (mWindowManager.mGlobalLock) {
+ updateDeferWakeTransition(false /* waiting */);
+ }
+ };
+
+ void updateDeferWakeTransition(boolean waiting) {
+ if (waiting == mWaitingForWakeTransition) {
+ return;
+ }
+ if (!mWindowManager.mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+ return;
+ }
+ // if aod is showing, defer the wake transition until aod state changed.
+ if (waiting && isAodShowing(DEFAULT_DISPLAY)) {
+ mWaitingForWakeTransition = true;
+ mWindowManager.mAtmService.getTransitionController().deferTransitionReady();
+ mWindowManager.mH.postDelayed(mResetWaitTransition, DEFER_WAKE_TRANSITION_TIMEOUT_MS);
+ } else if (!waiting) {
+ // dismiss the deferring if the aod state change or cancel awake.
+ mWaitingForWakeTransition = false;
+ mWindowManager.mAtmService.getTransitionController().continueTransitionReady();
+ mWindowManager.mH.removeCallbacks(mResetWaitTransition);
+ }
+ }
+
+
/** Represents Keyguard state per individual display. */
private static class KeyguardDisplayState {
private final int mDisplayId;
@@ -589,9 +621,7 @@ class KeyguardController {
mTopTurnScreenOnActivity = top;
}
- final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure(
- controller.mService.getCurrentUserId());
- if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) {
+ if (top.mDismissKeyguard && mKeyguardShowing) {
mKeyguardGoingAway = true;
} else if (top.canShowWhenLocked()) {
mTopOccludesActivity = top;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 40df02c176e5..b5eff41d4f62 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -25,7 +25,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.view.GestureDetector;
import android.view.InputChannel;
import android.view.InputEvent;
@@ -72,7 +71,8 @@ public class Letterbox {
private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow");
private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
// Reachability gestures.
- private final IntConsumer mDoubleTapCallback;
+ private final IntConsumer mDoubleTapCallbackX;
+ private final IntConsumer mDoubleTapCallbackY;
/**
* Constructs a Letterbox.
@@ -86,7 +86,8 @@ public class Letterbox {
Supplier<Boolean> hasWallpaperBackgroundSupplier,
Supplier<Integer> blurRadiusSupplier,
Supplier<Float> darkScrimAlphaSupplier,
- IntConsumer doubleTapCallback) {
+ IntConsumer doubleTapCallbackX,
+ IntConsumer doubleTapCallbackY) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mAreCornersRounded = areCornersRounded;
@@ -94,7 +95,8 @@ public class Letterbox {
mHasWallpaperBackgroundSupplier = hasWallpaperBackgroundSupplier;
mBlurRadiusSupplier = blurRadiusSupplier;
mDarkScrimAlphaSupplier = darkScrimAlphaSupplier;
- mDoubleTapCallback = doubleTapCallback;
+ mDoubleTapCallbackX = doubleTapCallbackX;
+ mDoubleTapCallbackY = doubleTapCallbackY;
}
/**
@@ -264,7 +266,8 @@ public class Letterbox {
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_UP) {
- mDoubleTapCallback.accept((int) e.getX());
+ mDoubleTapCallbackX.accept((int) e.getX());
+ mDoubleTapCallbackY.accept((int) e.getY());
return true;
}
return false;
@@ -293,8 +296,8 @@ public class Letterbox {
mWindowHandle.token = mToken;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.ownerPid = Process.myPid();
- mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mWindowHandle.ownerUid = WindowManagerService.MY_UID;
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SLIPPERY;
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index d02ad992c7e8..2d227b66b3ce 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -22,7 +22,6 @@ import android.content.Context;
import android.graphics.Color;
import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -38,6 +37,11 @@ final class LetterboxConfiguration {
*/
static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
+ // Min allowed aspect ratio for unresizable apps which is used when an app doesn't specify
+ // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ static final float MIN_UNRESIZABLE_ASPECT_RATIO = 4 / 3f;
+
/** Enum for Letterbox background type. */
@Retention(RetentionPolicy.SOURCE)
@IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
@@ -56,25 +60,48 @@ final class LetterboxConfiguration {
static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
/**
- * Enum for Letterbox reachability position types.
+ * Enum for Letterbox horizontal reachability position types.
*
* <p>Order from left to right is important since it's used in {@link
* #movePositionForReachabilityToNextRightStop} and {@link
* #movePositionForReachabilityToNextLeftStop}.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({LETTERBOX_REACHABILITY_POSITION_LEFT, LETTERBOX_REACHABILITY_POSITION_CENTER,
- LETTERBOX_REACHABILITY_POSITION_RIGHT})
- @interface LetterboxReachabilityPosition {};
+ @IntDef({LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT})
+ @interface LetterboxHorizontalReachabilityPosition {};
/** Letterboxed app window is aligned to the left side. */
- static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0;
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT = 0;
/** Letterboxed app window is positioned in the horizontal center. */
- static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1;
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER = 1;
+
+ /** Letterboxed app window is aligned to the right side. */
+ static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT = 2;
+
+ /**
+ * Enum for Letterbox vertical reachability position types.
+ *
+ * <p>Order from top to bottom is important since it's used in {@link
+ * #movePositionForReachabilityToNextBottomStop} and {@link
+ * #movePositionForReachabilityToNextTopStop}.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM})
+ @interface LetterboxVerticalReachabilityPosition {};
+
+ /** Letterboxed app window is aligned to the left side. */
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP = 0;
+
+ /** Letterboxed app window is positioned in the vertical center. */
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER = 1;
/** Letterboxed app window is aligned to the right side. */
- static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2;
+ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2;
final Context mContext;
@@ -82,6 +109,11 @@ final class LetterboxConfiguration {
// MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
private float mFixedOrientationLetterboxAspectRatio;
+ // Default min aspect ratio for unresizable apps which is used when an app doesn't specify
+ // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ private float mDefaultMinAspectRatioForUnresizableApps;
+
// Corners radius for activities presented in the letterbox mode, values < 0 will be ignored.
private int mLetterboxActivityCornersRadius;
@@ -107,29 +139,57 @@ final class LetterboxConfiguration {
// side of the screen and 1.0 to the right side.
private float mLetterboxHorizontalPositionMultiplier;
- // Default horizontal position the letterboxed app window when reachability is enabled and
- // an app is fullscreen in landscape device orientatio.
- // It is used as a starting point for mLetterboxPositionForReachability.
- @LetterboxReachabilityPosition
- private int mDefaultPositionForReachability;
+ // Vertical position of a center of the letterboxed app window. 0 corresponds to the top
+ // side of the screen and 1.0 to the bottom side.
+ private float mLetterboxVerticalPositionMultiplier;
+
+ // Default horizontal position the letterboxed app window when horizontal reachability is
+ // enabled and an app is fullscreen in landscape device orientation.
+ // It is used as a starting point for mLetterboxPositionForHorizontalReachability.
+ @LetterboxHorizontalReachabilityPosition
+ private int mDefaultPositionForHorizontalReachability;
+
+ // Default vertical position the letterboxed app window when vertical reachability is enabled
+ // and an app is fullscreen in portrait device orientation.
+ // It is used as a starting point for mLetterboxPositionForVerticalReachability.
+ @LetterboxVerticalReachabilityPosition
+ private int mDefaultPositionForVerticalReachability;
+
+ // Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in
+ // landscape device orientation.
+ private boolean mIsHorizontalReachabilityEnabled;
+
+ // Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
+ // portrait device orientation.
+ private boolean mIsVerticalReachabilityEnabled;
- // Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- // device orientation.
- private boolean mIsReachabilityEnabled;
// Horizontal position of a center of the letterboxed app window which is global to prevent
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
// LetterboxUiController#getHorizontalPositionMultiplier which is called from
- // ActivityRecord#updateResolvedBoundsHorizontalPosition.
+ // ActivityRecord#updateResolvedBoundsPosition.
+ // TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
+ // Overview after changing position in another app.
+ @LetterboxHorizontalReachabilityPosition
+ private volatile int mLetterboxPositionForHorizontalReachability;
+
+ // Vertical position of a center of the letterboxed app window which is global to prevent
+ // "jumps" when switching between letterboxed apps. It's updated to reposition the app window
+ // in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
+ // LetterboxUiController#getVerticalPositionMultiplier which is called from
+ // ActivityRecord#updateResolvedBoundsPosition.
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
// Overview after changing position in another app.
- @LetterboxReachabilityPosition
- private volatile int mLetterboxPositionForReachability;
+ @LetterboxVerticalReachabilityPosition
+ private volatile int mLetterboxPositionForVerticalReachability;
// Whether education is allowed for letterboxed fullscreen apps.
private boolean mIsEducationEnabled;
+ // Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
+ private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
+
LetterboxConfiguration(Context systemUiContext) {
mContext = systemUiContext;
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
@@ -143,12 +203,24 @@ final class LetterboxConfiguration {
R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
R.dimen.config_letterboxHorizontalPositionMultiplier);
- mIsReachabilityEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsReachabilityEnabled);
- mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
- mLetterboxPositionForReachability = mDefaultPositionForReachability;
+ mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat(
+ R.dimen.config_letterboxVerticalPositionMultiplier);
+ mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsHorizontalReachabilityEnabled);
+ mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsVerticalReachabilityEnabled);
+ mDefaultPositionForHorizontalReachability =
+ readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+ mDefaultPositionForVerticalReachability =
+ readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+ mLetterboxPositionForHorizontalReachability = mDefaultPositionForHorizontalReachability;
+ mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
mIsEducationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEducationEnabled);
+ setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
+ R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
}
/**
@@ -157,7 +229,6 @@ final class LetterboxConfiguration {
* com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
* the framework implementation will be used to determine the aspect ratio.
*/
- @VisibleForTesting
void setFixedOrientationLetterboxAspectRatio(float aspectRatio) {
mFixedOrientationLetterboxAspectRatio = aspectRatio;
}
@@ -166,7 +237,6 @@ final class LetterboxConfiguration {
* Resets the aspect ratio of letterbox for fixed orientation to {@link
* com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}.
*/
- @VisibleForTesting
void resetFixedOrientationLetterboxAspectRatio() {
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
@@ -180,6 +250,62 @@ final class LetterboxConfiguration {
}
/**
+ * Resets the min aspect ratio for unresizable apps which is used when an app doesn't specify
+ * {@code android:minAspectRatio} to {@link
+ * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps}.
+ *
+ * @throws AssertionError if {@link
+ * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps} is < {@link
+ * #MIN_UNRESIZABLE_ASPECT_RATIO}.
+ */
+ void resetDefaultMinAspectRatioForUnresizableApps() {
+ setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
+ R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
+ }
+
+ /**
+ * Gets the min aspect ratio for unresizable apps which is used when an app doesn't specify
+ * {@code android:minAspectRatio}.
+ */
+ float getDefaultMinAspectRatioForUnresizableApps() {
+ return mDefaultMinAspectRatioForUnresizableApps;
+ }
+
+ /**
+ * Overrides the min aspect ratio for unresizable apps which is used when an app doesn't
+ * specify {@code android:minAspectRatio}.
+ *
+ * @throws AssertionError if given value is < {@link #MIN_UNRESIZABLE_ASPECT_RATIO}.
+ */
+ void setDefaultMinAspectRatioForUnresizableApps(float aspectRatio) {
+ if (aspectRatio < MIN_UNRESIZABLE_ASPECT_RATIO) {
+ throw new AssertionError(
+ "Unexpected min aspect ratio for unresizable apps, it should be <= "
+ + MIN_UNRESIZABLE_ASPECT_RATIO + " but was " + aspectRatio);
+ }
+ mDefaultMinAspectRatioForUnresizableApps = aspectRatio;
+ }
+
+ /**
+ * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+ * both it and a value of {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
+ * corners of the activity won't be rounded.
+ */
+ void setLetterboxActivityCornersRadius(int cornersRadius) {
+ mLetterboxActivityCornersRadius = cornersRadius;
+ }
+
+ /**
+ * Resets corners raidus for activities presented in the letterbox mode to {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
+ */
+ void resetLetterboxActivityCornersRadius() {
+ mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_letterboxActivityCornersRadius);
+ }
+
+ /**
* Whether corners of letterboxed activities are rounded.
*/
boolean isLetterboxActivityCornersRounded() {
@@ -210,6 +336,34 @@ final class LetterboxConfiguration {
return Color.valueOf(mContext.getResources().getColor(colorId));
}
+
+ /**
+ * Sets color of letterbox background which is used when {@link
+ * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+ * fallback for other backfround types.
+ */
+ void setLetterboxBackgroundColor(Color color) {
+ mLetterboxBackgroundColorOverride = color;
+ }
+
+ /**
+ * Sets color ID of letterbox background which is used when {@link
+ * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+ * fallback for other backfround types.
+ */
+ void setLetterboxBackgroundColorResourceId(int colorId) {
+ mLetterboxBackgroundColorResourceIdOverride = colorId;
+ }
+
+ /**
+ * Resets color of letterbox background to {@link
+ * com.android.internal.R.color.config_letterboxBackgroundColor}.
+ */
+ void resetLetterboxBackgroundColor() {
+ mLetterboxBackgroundColorOverride = null;
+ mLetterboxBackgroundColorResourceIdOverride = null;
+ }
+
/**
* Gets {@link LetterboxBackgroundType} specified in {@link
* com.android.internal.R.integer.config_letterboxBackgroundType} or over via ADB command.
@@ -219,6 +373,19 @@ final class LetterboxConfiguration {
return mLetterboxBackgroundType;
}
+ /** Sets letterbox background type. */
+ void setLetterboxBackgroundType(@LetterboxBackgroundType int backgroundType) {
+ mLetterboxBackgroundType = backgroundType;
+ }
+
+ /**
+ * Resets cletterbox background type to {@link
+ * com.android.internal.R.integer.config_letterboxBackgroundType}.
+ */
+ void resetLetterboxBackgroundType() {
+ mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
+ }
+
/** Returns a string representing the given {@link LetterboxBackgroundType}. */
static String letterboxBackgroundTypeToString(
@LetterboxBackgroundType int backgroundType) {
@@ -248,6 +415,27 @@ final class LetterboxConfiguration {
}
/**
+ * Overrides alpha of a black scrim shown over wallpaper for {@link
+ * #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link mLetterboxBackgroundType}.
+ *
+ * <p>If given value is < 0 or >= 1, both it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored
+ * and 0.0 (transparent) is instead.
+ */
+ void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) {
+ mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha;
+ }
+
+ /**
+ * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}.
+ */
+ void resetLetterboxBackgroundWallpaperDarkScrimAlpha() {
+ mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
+ }
+
+ /**
* Gets alpha of a black scrim shown over wallpaper letterbox background.
*/
float getLetterboxBackgroundWallpaperDarkScrimAlpha() {
@@ -255,6 +443,28 @@ final class LetterboxConfiguration {
}
/**
+ * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in
+ * {@link mLetterboxBackgroundType}.
+ *
+ * <p> If given value <= 0, both it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored
+ * and 0 is used instead.
+ */
+ void setLetterboxBackgroundWallpaperBlurRadius(int radius) {
+ mLetterboxBackgroundWallpaperBlurRadius = radius;
+ }
+
+ /**
+ * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
+ * mLetterboxBackgroundType} to {@link
+ * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}.
+ */
+ void resetLetterboxBackgroundWallpaperBlurRadius() {
+ mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
+ }
+
+ /**
* Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
* mLetterboxBackgroundType}.
*/
@@ -275,72 +485,187 @@ final class LetterboxConfiguration {
? 0.5f : mLetterboxHorizontalPositionMultiplier;
}
+ /*
+ * Gets vertical position of a center of the letterboxed app window specified
+ * in {@link com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}
+ * or via an ADB command. 0 corresponds to the top side of the screen and 1 to the
+ * bottom side.
+ */
+ float getLetterboxVerticalPositionMultiplier() {
+ return (mLetterboxVerticalPositionMultiplier < 0.0f
+ || mLetterboxVerticalPositionMultiplier > 1.0f)
+ // Default to central position if invalid value is provided.
+ ? 0.5f : mLetterboxVerticalPositionMultiplier;
+ }
+
/**
* Overrides horizontal position of a center of the letterboxed app window. If given value < 0
* or > 1, then it and a value of {@link
* com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
* central position (0.5) is used.
*/
- @VisibleForTesting
void setLetterboxHorizontalPositionMultiplier(float multiplier) {
mLetterboxHorizontalPositionMultiplier = multiplier;
}
/**
+ * Overrides vertical position of a center of the letterboxed app window. If given value < 0
+ * or > 1, then it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} are ignored and
+ * central position (0.5) is used.
+ */
+ void setLetterboxVerticalPositionMultiplier(float multiplier) {
+ mLetterboxVerticalPositionMultiplier = multiplier;
+ }
+
+ /**
* Resets horizontal position of a center of the letterboxed app window to {@link
* com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
*/
- @VisibleForTesting
void resetLetterboxHorizontalPositionMultiplier() {
mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
}
+ /**
+ * Resets vertical position of a center of the letterboxed app window to {@link
+ * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}.
+ */
+ void resetLetterboxVerticalPositionMultiplier() {
+ mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier);
+ }
+
+ /*
+ * Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in
+ * landscape device orientation.
+ */
+ boolean getIsHorizontalReachabilityEnabled() {
+ return mIsHorizontalReachabilityEnabled;
+ }
+
/*
- * Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
- * device orientation.
+ * Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
+ * portrait device orientation.
*/
- boolean getIsReachabilityEnabled() {
- return mIsReachabilityEnabled;
+ boolean getIsVerticalReachabilityEnabled() {
+ return mIsVerticalReachabilityEnabled;
}
/**
- * Overrides whether reachability repositioning is allowed for letterboxed fullscreen apps in
- * landscape device orientation.
+ * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen
+ * apps in landscape device orientation.
+ */
+ void setIsHorizontalReachabilityEnabled(boolean enabled) {
+ mIsHorizontalReachabilityEnabled = enabled;
+ }
+
+ /**
+ * Overrides whether vertical reachability repositioning is allowed for letterboxed fullscreen
+ * apps in portrait device orientation.
+ */
+ void setIsVerticalReachabilityEnabled(boolean enabled) {
+ mIsVerticalReachabilityEnabled = enabled;
+ }
+
+ /**
+ * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen
+ * apps in landscape device orientation to
+ * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}.
*/
- @VisibleForTesting
- void setIsReachabilityEnabled(boolean enabled) {
- mIsReachabilityEnabled = enabled;
+ void resetIsHorizontalReachabilityEnabled() {
+ mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsHorizontalReachabilityEnabled);
}
/**
- * Resets whether reachability repositioning is allowed for letterboxed fullscreen apps in
- * landscape device orientation to {@link R.bool.config_letterboxIsReachabilityEnabled}.
+ * Resets whether vertical reachability repositioning is allowed for letterboxed fullscreen apps
+ * in portrait device orientation to
+ * {@link R.bool.config_letterboxIsVerticalReachabilityEnabled}.
*/
- @VisibleForTesting
- void resetIsReachabilityEnabled() {
- mIsReachabilityEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsReachabilityEnabled);
+ void resetIsVerticalReachabilityEnabled() {
+ mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsVerticalReachabilityEnabled);
}
/*
- * Gets default horizontal position of the letterboxed app window when reachability is enabled.
- * Specified in {@link R.integer.config_letterboxDefaultPositionForReachability} or via an ADB
- * command.
+ * Gets default horizontal position of the letterboxed app window when horizontal reachability
+ * is enabled.
+ *
+ * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}
+ * or via an ADB command.
+ */
+ @LetterboxHorizontalReachabilityPosition
+ int getDefaultPositionForHorizontalReachability() {
+ return mDefaultPositionForHorizontalReachability;
+ }
+
+ /*
+ * Gets default vertical position of the letterboxed app window when vertical reachability is
+ * enabled.
+ *
+ * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForVerticalReachability} or
+ * via an ADB command.
*/
- @LetterboxReachabilityPosition
- int getDefaultPositionForReachability() {
- return mDefaultPositionForReachability;
+ @LetterboxVerticalReachabilityPosition
+ int getDefaultPositionForVerticalReachability() {
+ return mDefaultPositionForVerticalReachability;
+ }
+
+ /**
+ * Overrides default horizontal position of the letterboxed app window when horizontal
+ * reachability is enabled.
+ */
+ void setDefaultPositionForHorizontalReachability(
+ @LetterboxHorizontalReachabilityPosition int position) {
+ mDefaultPositionForHorizontalReachability = position;
+ }
+
+ /**
+ * Overrides default vertical position of the letterboxed app window when vertical
+ * reachability is enabled.
+ */
+ void setDefaultPositionForVerticalReachability(
+ @LetterboxVerticalReachabilityPosition int position) {
+ mDefaultPositionForVerticalReachability = position;
+ }
+
+ /**
+ * Resets default horizontal position of the letterboxed app window when horizontal reachability
+ * is enabled to {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}.
+ */
+ void resetDefaultPositionForHorizontalReachability() {
+ mDefaultPositionForHorizontalReachability =
+ readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+ }
+
+ /**
+ * Resets default vertical position of the letterboxed app window when vertical reachability
+ * is enabled to {@link R.integer.config_letterboxDefaultPositionForVerticalReachability}.
+ */
+ void resetDefaultPositionForVerticalReachability() {
+ mDefaultPositionForVerticalReachability =
+ readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+ }
+
+ @LetterboxHorizontalReachabilityPosition
+ private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context) {
+ int position = context.getResources().getInteger(
+ R.integer.config_letterboxDefaultPositionForHorizontalReachability);
+ return position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT
+ || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER
+ || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT
+ ? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
}
- @LetterboxReachabilityPosition
- private static int readLetterboxReachabilityPositionFromConfig(Context context) {
+ @LetterboxVerticalReachabilityPosition
+ private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context) {
int position = context.getResources().getInteger(
- R.integer.config_letterboxDefaultPositionForReachability);
- return position == LETTERBOX_REACHABILITY_POSITION_LEFT
- || position == LETTERBOX_REACHABILITY_POSITION_CENTER
- || position == LETTERBOX_REACHABILITY_POSITION_RIGHT
- ? position : LETTERBOX_REACHABILITY_POSITION_CENTER;
+ R.integer.config_letterboxDefaultPositionForVerticalReachability);
+ return position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP
+ || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER
+ || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM
+ ? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
}
/*
@@ -350,48 +675,108 @@ final class LetterboxConfiguration {
* <p>The position multiplier is changed after each double tap in the letterbox area.
*/
float getHorizontalMultiplierForReachability() {
- switch (mLetterboxPositionForReachability) {
- case LETTERBOX_REACHABILITY_POSITION_LEFT:
+ switch (mLetterboxPositionForHorizontalReachability) {
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
+ return 0.0f;
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
+ return 0.5f;
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
+ return 1.0f;
+ default:
+ throw new AssertionError(
+ "Unexpected letterbox position type: "
+ + mLetterboxPositionForHorizontalReachability);
+ }
+ }
+ /*
+ * Gets vertical position of a center of the letterboxed app window when reachability
+ * is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side.
+ *
+ * <p>The position multiplier is changed after each double tap in the letterbox area.
+ */
+ float getVerticalMultiplierForReachability() {
+ switch (mLetterboxPositionForVerticalReachability) {
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
return 0.0f;
- case LETTERBOX_REACHABILITY_POSITION_CENTER:
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
return 0.5f;
- case LETTERBOX_REACHABILITY_POSITION_RIGHT:
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
return 1.0f;
default:
throw new AssertionError(
- "Unexpected letterbox position type: " + mLetterboxPositionForReachability);
+ "Unexpected letterbox position type: "
+ + mLetterboxPositionForVerticalReachability);
}
}
- /** Returns a string representing the given {@link LetterboxReachabilityPosition}. */
- static String letterboxReachabilityPositionToString(
- @LetterboxReachabilityPosition int position) {
+ /** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
+ static String letterboxHorizontalReachabilityPositionToString(
+ @LetterboxHorizontalReachabilityPosition int position) {
switch (position) {
- case LETTERBOX_REACHABILITY_POSITION_LEFT:
- return "LETTERBOX_REACHABILITY_POSITION_LEFT";
- case LETTERBOX_REACHABILITY_POSITION_CENTER:
- return "LETTERBOX_REACHABILITY_POSITION_CENTER";
- case LETTERBOX_REACHABILITY_POSITION_RIGHT:
- return "LETTERBOX_REACHABILITY_POSITION_RIGHT";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER";
+ case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
+ return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT";
default:
throw new AssertionError(
"Unexpected letterbox position type: " + position);
}
}
+ /** Returns a string representing the given {@link LetterboxVerticalReachabilityPosition}. */
+ static String letterboxVerticalReachabilityPositionToString(
+ @LetterboxVerticalReachabilityPosition int position) {
+ switch (position) {
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP";
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER";
+ case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
+ return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM";
+ default:
+ throw new AssertionError(
+ "Unexpected letterbox position type: " + position);
+ }
+ }
+
+ /**
+ * Changes letterbox position for horizontal reachability to the next available one on the
+ * right side.
+ */
+ void movePositionForHorizontalReachabilityToNextRightStop() {
+ mLetterboxPositionForHorizontalReachability = Math.min(
+ mLetterboxPositionForHorizontalReachability + 1,
+ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT);
+ }
+
/**
- * Changes letterbox position for reachability to the next available one on the right side.
+ * Changes letterbox position for horizontal reachability to the next available one on the left
+ * side.
*/
- void movePositionForReachabilityToNextRightStop() {
- mLetterboxPositionForReachability = Math.min(
- mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT);
+ void movePositionForHorizontalReachabilityToNextLeftStop() {
+ mLetterboxPositionForHorizontalReachability =
+ Math.max(mLetterboxPositionForHorizontalReachability - 1, 0);
}
/**
- * Changes letterbox position for reachability to the next available one on the left side.
+ * Changes letterbox position for vertical reachability to the next available one on the bottom
+ * side.
*/
- void movePositionForReachabilityToNextLeftStop() {
- mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0);
+ void movePositionForVerticalReachabilityToNextBottomStop() {
+ mLetterboxPositionForVerticalReachability = Math.min(
+ mLetterboxPositionForVerticalReachability + 1,
+ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM);
+ }
+
+ /**
+ * Changes letterbox position for vertical reachability to the next available one on the top
+ * side.
+ */
+ void movePositionForVerticalReachabilityToNextTopStop() {
+ mLetterboxPositionForVerticalReachability =
+ Math.max(mLetterboxPositionForVerticalReachability - 1, 0);
}
/**
@@ -404,8 +789,41 @@ final class LetterboxConfiguration {
/**
* Overrides whether education is allowed for letterboxed fullscreen apps.
*/
- @VisibleForTesting
void setIsEducationEnabled(boolean enabled) {
mIsEducationEnabled = enabled;
}
+
+ /**
+ * Resets whether education is allowed for letterboxed fullscreen apps to
+ * {@link R.bool.config_letterboxIsEducationEnabled}.
+ */
+ void resetIsEducationEnabled() {
+ mIsEducationEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsEducationEnabled);
+ }
+
+ /**
+ * Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
+ */
+ boolean getIsSplitScreenAspectRatioForUnresizableAppsEnabled() {
+ return mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
+ }
+
+ /**
+ * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable
+ * apps.
+ */
+ void setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled) {
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = enabled;
+ }
+
+ /**
+ * Resets whether using split screen aspect ratio as a default aspect ratio for unresizable
+ * apps {@link R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}.
+ */
+ void resetIsSplitScreenAspectRatioForUnresizableAppsEnabled() {
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index bb15d76c3bac..df9a87ea1ab0 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -163,7 +163,8 @@ final class LetterboxUiController {
this::hasWallpaperBackgroudForLetterbox,
this::getLetterboxWallpaperBlurRadius,
this::getLetterboxWallpaperDarkScrimAlpha,
- this::handleDoubleTap);
+ this::handleHorizontalDoubleTap,
+ this::handleVerticalDoubleTap);
mLetterbox.attachInput(w);
}
mActivityRecord.getPosition(mTmpPoint);
@@ -193,18 +194,27 @@ final class LetterboxUiController {
float getHorizontalPositionMultiplier(Configuration parentConfiguration) {
// Don't check resolved configuration because it may not be updated yet during
// configuration change.
- return isReachabilityEnabled(parentConfiguration)
+ return isHorizontalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
? mLetterboxConfiguration.getHorizontalMultiplierForReachability()
: mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
}
- float getFixedOrientationLetterboxAspectRatio(Configuration parentConfiguration) {
- // Don't check resolved windowing mode because it may not be updated yet during
+ float getVerticalPositionMultiplier(Configuration parentConfiguration) {
+ // Don't check resolved configuration because it may not be updated yet during
// configuration change.
- if (!isReachabilityEnabled(parentConfiguration)) {
- return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ return isVerticalReachabilityEnabled(parentConfiguration)
+ // Using the last global dynamic position to avoid "jumps" when moving
+ // between apps or activities.
+ ? mLetterboxConfiguration.getVerticalMultiplierForReachability()
+ : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier();
+ }
+
+ float getDefaultMinAspectRatioForUnresizableApps() {
+ if (!mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled()
+ || mActivityRecord.getDisplayContent() == null) {
+ return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps();
}
int dividerWindowWidth =
@@ -214,10 +224,14 @@ final class LetterboxUiController {
int dividerSize = dividerWindowWidth - dividerInsets * 2;
// Getting the same aspect ratio that apps get in split screen.
- Rect bounds = new Rect(parentConfiguration.windowConfiguration.getAppBounds());
- bounds.inset(dividerSize, /* dy */ 0);
- bounds.right = bounds.centerX();
-
+ Rect bounds = new Rect(mActivityRecord.getDisplayContent().getBounds());
+ if (bounds.width() >= bounds.height()) {
+ bounds.inset(/* dx */ dividerSize, /* dy */ 0);
+ bounds.right = bounds.centerX();
+ } else {
+ bounds.inset(/* dx */ 0, /* dy */ dividerSize);
+ bounds.bottom = bounds.centerY();
+ }
return computeAspectRatio(bounds);
}
@@ -225,8 +239,8 @@ final class LetterboxUiController {
return mActivityRecord.mWmService.mContext.getResources();
}
- private void handleDoubleTap(int x) {
- if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) {
+ private void handleHorizontalDoubleTap(int x) {
+ if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
@@ -237,10 +251,32 @@ final class LetterboxUiController {
if (mLetterbox.getInnerFrame().left > x) {
// Moving to the next stop on the left side of the app window: right > center > left.
- mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop();
+ mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextLeftStop();
} else if (mLetterbox.getInnerFrame().right < x) {
// Moving to the next stop on the right side of the app window: left > center > right.
- mLetterboxConfiguration.movePositionForReachabilityToNextRightStop();
+ mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
+ }
+
+ // TODO(197549949): Add animation for transition.
+ mActivityRecord.recomputeConfiguration();
+ }
+
+ private void handleVerticalDoubleTap(int y) {
+ if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) {
+ return;
+ }
+
+ if (mLetterbox.getInnerFrame().top <= y && mLetterbox.getInnerFrame().bottom >= y) {
+ // Only react to clicks at the top and bottom of the letterboxed app window.
+ return;
+ }
+
+ if (mLetterbox.getInnerFrame().top > y) {
+ // Moving to the next stop on the top side of the app window: bottom > center > top.
+ mLetterboxConfiguration.movePositionForVerticalReachabilityToNextTopStop();
+ } else if (mLetterbox.getInnerFrame().bottom < y) {
+ // Moving to the next stop on the bottom side of the app window: top > center > bottom.
+ mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
}
// TODO(197549949): Add animation for transition.
@@ -248,25 +284,47 @@ final class LetterboxUiController {
}
/**
- * Whether reachability is enabled for an activity in the curren configuration.
+ * Whether horizontal reachability is enabled for an activity in the current configuration.
*
* <p>Conditions that needs to be met:
* <ul>
* <li>Activity is portrait-only.
* <li>Fullscreen window in landscape device orientation.
- * <li>Reachability is enabled.
+ * <li>Horizontal Reachability is enabled.
+ * </ul>
+ */
+ private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
+ return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
+ && parentConfiguration.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_FULLSCREEN
+ && (parentConfiguration.orientation == ORIENTATION_LANDSCAPE
+ && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT);
+ }
+
+ private boolean isHorizontalReachabilityEnabled() {
+ return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
+ }
+
+ /**
+ * Whether vertical reachability is enabled for an activity in the current configuration.
+ *
+ * <p>Conditions that needs to be met:
+ * <ul>
+ * <li>Activity is landscape-only.
+ * <li>Fullscreen window in portrait device orientation.
+ * <li>Vertical Reachability is enabled.
* </ul>
*/
- private boolean isReachabilityEnabled(Configuration parentConfiguration) {
- return mLetterboxConfiguration.getIsReachabilityEnabled()
+ private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
+ return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
- && parentConfiguration.orientation == ORIENTATION_LANDSCAPE
- && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
+ && (parentConfiguration.orientation == ORIENTATION_PORTRAIT
+ && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_LANDSCAPE);
}
- private boolean isReachabilityEnabled() {
- return isReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
+ private boolean isVerticalReachabilityEnabled() {
+ return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
@VisibleForTesting
@@ -474,12 +532,19 @@ final class LetterboxUiController {
+ getLetterboxWallpaperBlurRadius());
}
- pw.println(prefix + " isReachabilityEnabled=" + isReachabilityEnabled());
+ pw.println(prefix + " isHorizontalReachabilityEnabled="
+ + isHorizontalReachabilityEnabled());
+ pw.println(prefix + " isVerticalReachabilityEnabled=" + isVerticalReachabilityEnabled());
pw.println(prefix + " letterboxHorizontalPositionMultiplier="
+ getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
+ pw.println(prefix + " letterboxVerticalPositionMultiplier="
+ + getVerticalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
pw.println(prefix + " fixedOrientationLetterboxAspectRatio="
- + getFixedOrientationLetterboxAspectRatio(
- mActivityRecord.getParent().getConfiguration()));
+ + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+ pw.println(prefix + " defaultMinAspectRatioForUnresizableApps="
+ + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
+ pw.println(prefix + " isSplitScreenAspectRatioForUnresizableAppsEnabled="
+ + mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
}
/**
@@ -496,6 +561,9 @@ final class LetterboxUiController {
if (mainWin.isLetterboxedForDisplayCutout()) {
return "DISPLAY_CUTOUT";
}
+ if (mActivityRecord.isAspectRatioApplied()) {
+ return "ASPECT_RATIO";
+ }
return "UNKNOWN_REASON";
}
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 9c1d5601dad5..d209f08e6312 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -22,17 +22,21 @@ import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.HandlerExecutor;
+import android.window.DisplayAreaInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
public class PhysicalDisplaySwitchTransitionLauncher {
private final DisplayContent mDisplayContent;
+ private final WindowManagerService mService;
private final DeviceStateManager mDeviceStateManager;
- private final Context mContext;
private final TransitionController mTransitionController;
private DeviceStateListener mDeviceStateListener;
@@ -46,13 +50,13 @@ public class PhysicalDisplaySwitchTransitionLauncher {
public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
TransitionController transitionController) {
mDisplayContent = displayContent;
- mContext = mDisplayContent.mWmService.mContext;
+ mService = displayContent.mWmService;
mTransitionController = transitionController;
- mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+ mDeviceStateManager = mService.mContext.getSystemService(DeviceStateManager.class);
if (mDeviceStateManager != null) {
- mDeviceStateListener = new DeviceStateListener(mContext);
+ mDeviceStateListener = new DeviceStateListener(mService.mContext);
mDeviceStateManager
.registerCallback(new HandlerExecutor(mDisplayContent.mWmService.mH),
mDeviceStateListener);
@@ -74,7 +78,7 @@ public class PhysicalDisplaySwitchTransitionLauncher {
if (!mDisplayContent.getLastHasContent()) return;
boolean shouldRequestUnfoldTransition = !mIsFolded
- && mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
+ && mService.mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
&& ValueAnimator.areAnimatorsEnabled();
if (!shouldRequestUnfoldTransition) {
@@ -102,11 +106,42 @@ public class PhysicalDisplaySwitchTransitionLauncher {
}
}
- public void onDisplayUpdated() {
- if (mTransition != null) {
- mTransition.setAllReady();
- mTransition = null;
+ /**
+ * Called when physical display is getting updated, this could happen e.g. on foldable
+ * devices when the physical underlying display is replaced.
+ *
+ * @param fromRotation rotation before the display change
+ * @param toRotation rotation after the display change
+ * @param newDisplayAreaInfo display area info after the display change
+ */
+ public void onDisplayUpdated(int fromRotation, int toRotation,
+ @NonNull DisplayAreaInfo newDisplayAreaInfo) {
+ if (mTransition == null) return;
+
+ final boolean started = mDisplayContent.mRemoteDisplayChangeController
+ .performRemoteDisplayChange(fromRotation, toRotation, newDisplayAreaInfo,
+ this::continueDisplayUpdate);
+
+ if (!started) {
+ markTransitionAsReady();
+ }
+ }
+
+ private void continueDisplayUpdate(@Nullable WindowContainerTransaction transaction) {
+ if (mTransition == null) return;
+
+ if (transaction != null) {
+ mService.mAtmService.mWindowOrganizerController.applyTransaction(transaction);
}
+
+ markTransitionAsReady();
+ }
+
+ private void markTransitionAsReady() {
+ if (mTransition == null) return;
+
+ mTransition.setAllReady();
+ mTransition = null;
}
class DeviceStateListener extends DeviceStateManager.FoldStateListener {
diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
new file mode 100644
index 000000000000..43baebc7255a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.IDisplayChangeWindowCallback;
+import android.window.DisplayAreaInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class, a wrapper around {@link android.view.IDisplayChangeWindowController} to perform
+ * a synchronous display change in other parts (e.g. in the Shell) and continue the process
+ * in the system server. It handles timeouts and multiple requests.
+ * We have an instance of this controller for each display.
+ */
+public class RemoteDisplayChangeController {
+
+ private static final String TAG = "RemoteDisplayChangeController";
+
+ private static final int REMOTE_DISPLAY_CHANGE_TIMEOUT_MS = 800;
+
+ private final WindowManagerService mService;
+ private final int mDisplayId;
+
+ private final Runnable mTimeoutRunnable = this::onContinueTimedOut;
+
+ // all remote changes that haven't finished yet.
+ private final List<ContinueRemoteDisplayChangeCallback> mCallbacks = new ArrayList<>();
+
+ public RemoteDisplayChangeController(WindowManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ }
+
+ /**
+ * A Remote change is when we are waiting for some registered (remote)
+ * {@link IDisplayChangeWindowController} to calculate and return some hierarchy operations
+ * to perform in sync with the display change.
+ */
+ public boolean isWaitingForRemoteDisplayChange() {
+ return !mCallbacks.isEmpty();
+ }
+
+ /**
+ * Starts remote display change
+ * @param fromRotation rotation before the change
+ * @param toRotation rotation after the change
+ * @param newDisplayAreaInfo display area info after change
+ * @param callback that will be called after completing remote display change
+ * @return true if the change successfully started, false otherwise
+ */
+ public boolean performRemoteDisplayChange(
+ int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo,
+ ContinueRemoteDisplayChangeCallback callback) {
+ if (mService.mDisplayChangeController == null) {
+ return false;
+ }
+ mCallbacks.add(callback);
+
+ if (newDisplayAreaInfo != null) {
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Starting remote display change: "
+ + "from [rot = %d], "
+ + "to [%dx%d, rot = %d]",
+ fromRotation,
+ newDisplayAreaInfo.configuration.windowConfiguration
+ .getMaxBounds().width(),
+ newDisplayAreaInfo.configuration.windowConfiguration
+ .getMaxBounds().height(),
+ toRotation);
+ }
+
+ final IDisplayChangeWindowCallback remoteCallback = createCallback(callback);
+ try {
+ mService.mH.removeCallbacks(mTimeoutRunnable);
+ mService.mH.postDelayed(mTimeoutRunnable, REMOTE_DISPLAY_CHANGE_TIMEOUT_MS);
+ mService.mDisplayChangeController.onDisplayChange(mDisplayId, fromRotation, toRotation,
+ newDisplayAreaInfo, remoteCallback);
+ return true;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while dispatching remote display-change", e);
+ mCallbacks.remove(callback);
+ return false;
+ }
+ }
+
+ private void onContinueTimedOut() {
+ Slog.e(TAG, "RemoteDisplayChange timed-out, UI might get messed-up after this.");
+ // timed-out, so run all continue callbacks and clear the list
+ synchronized (mService.mGlobalLock) {
+ for (int i = 0; i < mCallbacks.size(); ++i) {
+ mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
+ }
+ mCallbacks.clear();
+ }
+ }
+
+ private void continueDisplayChange(@NonNull ContinueRemoteDisplayChangeCallback callback,
+ @Nullable WindowContainerTransaction transaction) {
+ synchronized (mService.mGlobalLock) {
+ int idx = mCallbacks.indexOf(callback);
+ if (idx < 0) {
+ // already called this callback or a more-recent one (eg. via timeout)
+ return;
+ }
+ for (int i = 0; i < idx; ++i) {
+ // Expect remote callbacks in order. If they don't come in order, then force
+ // ordering by continuing everything up until this one with empty transactions.
+ mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
+ }
+ mCallbacks.subList(0, idx + 1).clear();
+ if (mCallbacks.isEmpty()) {
+ mService.mH.removeCallbacks(mTimeoutRunnable);
+ }
+ callback.onContinueRemoteDisplayChange(transaction);
+ }
+ }
+
+ private IDisplayChangeWindowCallback createCallback(
+ @NonNull ContinueRemoteDisplayChangeCallback callback) {
+ return new IDisplayChangeWindowCallback.Stub() {
+ @Override
+ public void continueDisplayChange(WindowContainerTransaction t) {
+ synchronized (mService.mGlobalLock) {
+ if (!mCallbacks.contains(callback)) {
+ // already ran this callback or a more-recent one.
+ return;
+ }
+ mService.mH.post(() -> RemoteDisplayChangeController.this
+ .continueDisplayChange(callback, t));
+ }
+ }
+ };
+ }
+
+ /**
+ * Callback interface to handle continuation of the remote display change
+ */
+ public interface ContinueRemoteDisplayChangeCallback {
+ /**
+ * This method is called when the remote display change has been applied
+ * @param transaction window changes collected by the remote display change
+ */
+ void onContinueRemoteDisplayChange(@Nullable WindowContainerTransaction transaction);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ef18b50e910b..326c450f4d5c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1977,23 +1977,28 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
@Nullable ActivityRecord launchIntoPipHostActivity, String reason) {
- mService.deferWindowLayout();
+ moveActivityToPinnedRootTask(r, launchIntoPipHostActivity, reason, null /* transition */);
+ }
+ void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
+ @Nullable ActivityRecord launchIntoPipHostActivity, String reason,
+ @Nullable Transition transition) {
final TaskDisplayArea taskDisplayArea = r.getDisplayArea();
+ final Task task = r.getTask();
+ final Task rootTask;
- try {
- final Task task = r.getTask();
-
- // Create a transition now to collect the current pinned Task dismiss. Only do the
- // create here as the Task (trigger) to enter PIP is not ready yet.
- final TransitionController transitionController = task.mTransitionController;
- Transition newTransition = null;
- if (transitionController.isCollecting()) {
- transitionController.setReady(task, false /* ready */);
- } else if (transitionController.getTransitionPlayer() != null) {
- newTransition = transitionController.createTransition(TRANSIT_PIP);
- }
+ Transition newTransition = transition;
+ // Create a transition now (if not provided) to collect the current pinned Task dismiss.
+ // Only do the create here as the Task (trigger) to enter PIP is not ready yet.
+ final TransitionController transitionController = task.mTransitionController;
+ if (newTransition == null && !transitionController.isCollecting()
+ && transitionController.getTransitionPlayer() != null) {
+ newTransition = transitionController.createTransition(TRANSIT_PIP);
+ }
+ transitionController.deferTransitionReady();
+ mService.deferWindowLayout();
+ try {
// This will change the root pinned task's windowing mode to its original mode, ensuring
// we only have one root task that is in pinned mode.
final Task rootPinnedTask = taskDisplayArea.getRootPinnedTask();
@@ -2011,7 +2016,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final TaskFragment organizedTf = r.getOrganizedTaskFragment();
final boolean singleActivity = task.getNonFinishingActivityCount() == 1;
- final Task rootTask;
if (singleActivity) {
rootTask = task;
@@ -2044,6 +2048,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
task.mLastRecentsAnimationTransaction,
task.mLastRecentsAnimationOverlay);
task.clearLastRecentsAnimationTransaction(false /* forceRemoveOverlay */);
+ } else {
+ // Reset the original task surface
+ task.resetSurfaceControlTransforms();
}
// The organized TaskFragment is becoming empty because this activity is reparented
@@ -2077,6 +2084,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
oldTopActivity.mRequestForceTransition = true;
}
}
+
+ transitionController.collect(rootTask);
+
// The intermediate windowing mode to be set on the ActivityRecord later.
// This needs to happen before the re-parenting, otherwise we will always set the
// ActivityRecord to be fullscreen.
@@ -2087,13 +2097,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
rootTask.reparent(taskDisplayArea, true /* onTop */);
}
- // The new PIP Task is ready, start the transition before updating the windowing mode.
- if (newTransition != null) {
- transitionController.requestStartTransition(newTransition, rootTask,
- null /* remoteTransition */, null /* displayChange */);
- }
- transitionController.collect(rootTask);
-
// Defer the windowing mode change until after the transition to prevent the activity
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
@@ -2136,9 +2139,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
} finally {
mService.continueWindowLayout();
+ try {
+ ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+ } finally {
+ transitionController.continueTransitionReady();
+ }
+ }
+
+ if (newTransition != null) {
+ // Request at end since we want task-organizer events from ensureActivitiesVisible
+ // to be recognized.
+ transitionController.requestStartTransition(newTransition, rootTask,
+ null /* remoteTransition */, null /* displayChange */);
+ // A new transition was created just for this operations. Since the operation is
+ // complete, mark it as ready.
+ newTransition.setReady(rootTask, true /* ready */);
}
- ensureActivitiesVisible(null, 0, false /* preserveWindows */);
resumeFocusedTasksTopActivities();
notifyActivityPipModeChanged(r.getTask(), r);
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 2d4aef682d62..baa31a073dd2 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.STATUS_BAR_SERVICE;
@@ -172,7 +173,7 @@ public class SafeActivityOptions {
if (adapter == null) {
return;
}
- if (callingPid == Process.myPid()) {
+ if (callingPid == WindowManagerService.MY_PID) {
Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
return;
}
@@ -297,6 +298,20 @@ public class SafeActivityOptions {
}
}
+ // Check if the caller is allowed to dismiss keyguard.
+ final boolean dismissKeyguard = options.getDismissKeyguard();
+ if (aInfo != null && dismissKeyguard) {
+ final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission(
+ CONTROL_KEYGUARD, callingPid, callingUid);
+ if (controlKeyguardPerm != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: starting " + getIntentString(intent)
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with dismissKeyguard=true";
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+
// Check permission for remote animations
final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
if (adapter != null && supervisor.mService.checkPermission(
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 518bfd4c90df..2ef19321d958 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -164,6 +164,10 @@ class ScreenRotationAnimation {
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
+ // Exclude rounded corner overlay from screenshot buffer. Rounded
+ // corner overlay windows are un-rotated during rotation animation
+ // for a seamless transition.
+ .setExcludeLayers(displayContent.findRoundedCornerOverlays())
.build();
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
SurfaceControl.captureLayers(args);
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index e8445ab8c35e..68dbb0607ac1 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -221,6 +221,11 @@ public class StartingSurfaceController {
// Attempt to add starting window from the top-most activity.
for (int i = mDeferringAddStartActivities.size() - 1; i >= 0; --i) {
final DeferringStartingWindowRecord next = mDeferringAddStartActivities.get(i);
+ if (next.mDeferring.getTask() == null) {
+ Slog.e(TAG, "No task exists: " + next.mDeferring.shortComponentName
+ + " parent: " + next.mDeferring.getParent());
+ continue;
+ }
next.mDeferring.showStartingWindow(next.mPrev, mInitNewTask, mInitTaskSwitch,
mInitProcessRunning, true /* startActivity */, next.mSource, topOptions);
// If one succeeds, it is done.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bf5246f2339a..7c1488b71bf5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -67,6 +67,7 @@ import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
@@ -76,7 +77,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
@@ -197,6 +197,7 @@ import android.window.WindowContainerToken;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -426,9 +427,6 @@ class Task extends TaskFragment {
/** Helper object used for updating override configuration. */
private Configuration mTmpConfig = new Configuration();
- /** Used by fillTaskInfo */
- final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
-
/* Unique identifier for this task. */
final int mTaskId;
/* User for which this task was created. */
@@ -1404,15 +1402,6 @@ class Task extends TaskFragment {
}
/**
- * Return the number of running activities, and the number of non-finishing/initializing
- * activities in the provided {@param reportOut} respectively.
- */
- private void getNumRunningActivities(TaskActivitiesReport reportOut) {
- reportOut.reset();
- forAllActivities(reportOut);
- }
-
- /**
* Reorder the history task so that the passed activity is brought to the front.
*/
final void moveActivityToFrontLocked(ActivityRecord newTop) {
@@ -1707,23 +1696,6 @@ class Task extends TaskFragment {
lockTaskAuthToString());
}
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- return supportsSplitScreenWindowingModeInDisplayArea(getDisplayArea());
- }
-
- boolean supportsSplitScreenWindowingModeInDisplayArea(@Nullable TaskDisplayArea tda) {
- final Task topTask = getTopMostTask();
- return super.supportsSplitScreenWindowingMode()
- && (topTask == null || topTask.supportsSplitScreenWindowingModeInner(tda));
- }
-
- private boolean supportsSplitScreenWindowingModeInner(@Nullable TaskDisplayArea tda) {
- return super.supportsSplitScreenWindowingMode()
- && mAtmService.mSupportsSplitScreenMultiWindow
- && supportsMultiWindowInDisplayArea(tda);
- }
-
boolean supportsFreeform() {
return supportsFreeformInDisplayArea(getDisplayArea());
}
@@ -2031,10 +2003,6 @@ class Task extends TaskFragment {
Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- if (!isOrganized()) {
- // Use empty bounds to indicate "fill parent".
- outOverrideBounds.setEmpty();
- }
// The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
// the parent or display is smaller than the size, the content may be cropped.
return;
@@ -3384,14 +3352,14 @@ class Task extends TaskFragment {
* the give {@link TaskDisplayArea}.
*/
void fillTaskInfo(TaskInfo info, boolean stripExtras, @Nullable TaskDisplayArea tda) {
- getNumRunningActivities(mReuseActivitiesReport);
+ info.launchCookies.clear();
+ info.addLaunchCookie(mLaunchCookie);
+ final ActivityRecord top = mTaskSupervisor.mTaskInfoHelper.fillAndReturnTop(this, info);
+
info.userId = isLeafTask() ? mUserId : mCurrentUser;
info.taskId = mTaskId;
info.displayId = getDisplayId();
- if (tda != null) {
- info.displayAreaFeatureId = tda.mFeatureId;
- }
- info.isRunning = getTopNonFinishingActivity() != null;
+ info.displayAreaFeatureId = tda != null ? tda.mFeatureId : FEATURE_UNDEFINED;
final Intent baseIntent = getBaseIntent();
// Make a copy of base intent because this is like a snapshot info.
// Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
@@ -3400,18 +3368,13 @@ class Task extends TaskFragment {
? new Intent()
: stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent);
info.baseIntent.setFlags(baseIntentFlags);
- info.baseActivity = mReuseActivitiesReport.base != null
- ? mReuseActivitiesReport.base.intent.getComponent()
- : null;
- info.topActivity = mReuseActivitiesReport.top != null
- ? mReuseActivitiesReport.top.mActivityComponent
- : null;
+
+ info.isRunning = top != null;
+ info.topActivity = top != null ? top.mActivityComponent : null;
info.origActivity = origActivity;
info.realActivity = realActivity;
- info.numActivities = mReuseActivitiesReport.numActivities;
info.lastActiveTime = lastActiveTime;
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
- info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingModeInDisplayArea(tda);
info.supportsMultiWindow = supportsMultiWindowInDisplayArea(tda);
info.configuration.setTo(getConfiguration());
// Update to the task's current activity type and windowing mode which may differ from the
@@ -3422,49 +3385,38 @@ class Task extends TaskFragment {
//TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
// order changes.
- final Task top = getTopMostTask();
- info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
- info.topActivityType = top.getActivityType();
+ final Task topTask = top != null ? top.getTask() : this;
+ info.resizeMode = topTask.mResizeMode;
+ info.topActivityType = topTask.getActivityType();
+ info.displayCutoutInsets = topTask.getDisplayCutoutInsets();
info.isResizeable = isResizeable();
info.minWidth = mMinWidth;
info.minHeight = mMinHeight;
info.defaultMinSize = mDisplayContent == null
? DEFAULT_MIN_TASK_SIZE_DP : mDisplayContent.mMinSizeOfResizeableTaskDp;
-
info.positionInParent = getRelativePosition();
+ info.topActivityInfo = top != null ? top.info : null;
info.pictureInPictureParams = getPictureInPictureParams(top);
- info.shouldDockBigOverlays = shouldDockBigOverlays();
- if (info.pictureInPictureParams != null
+ info.launchIntoPipHostTaskId = (info.pictureInPictureParams != null
&& info.pictureInPictureParams.isLaunchIntoPip()
- && top.getTopMostActivity().getLastParentBeforePip() != null) {
- info.launchIntoPipHostTaskId =
- top.getTopMostActivity().getLastParentBeforePip().mTaskId;
- }
- info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null;
- info.topActivityInfo = mReuseActivitiesReport.top != null
- ? mReuseActivitiesReport.top.info
- : null;
-
- boolean isTopActivityResumed = mReuseActivitiesReport.top != null
- && mReuseActivitiesReport.top.getOrganizedTask() == this
- && mReuseActivitiesReport.top.isState(RESUMED);
+ && top.getLastParentBeforePip() != null)
+ ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
+ info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays;
+ info.mTopActivityLocusId = top != null ? top.getLocusId() : null;
+
+ final boolean isTopActivityResumed = top != null
+ && top.getOrganizedTask() == this && top.isState(RESUMED);
// Whether the direct top activity is in size compat mode on foreground.
- info.topActivityInSizeCompat = isTopActivityResumed
- && mReuseActivitiesReport.top.inSizeCompatMode();
+ info.topActivityInSizeCompat = isTopActivityResumed && top.inSizeCompatMode();
// Whether the direct top activity is eligible for letterbox education.
info.topActivityEligibleForLetterboxEducation = isTopActivityResumed
- && mReuseActivitiesReport.top.isEligibleForLetterboxEducation();
+ && top.isEligibleForLetterboxEducation();
// Whether the direct top activity requested showing camera compat control.
info.cameraCompatControlState = isTopActivityResumed
- ? mReuseActivitiesReport.top.getCameraCompatControlState()
+ ? top.getCameraCompatControlState()
: TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
- info.launchCookies.clear();
- info.addLaunchCookie(mLaunchCookie);
- forAllActivities(r -> {
- info.addLaunchCookie(r.mLaunchCookie);
- });
final Task parentTask = getParent() != null ? getParent().asTask() : null;
info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer
? parentTask.mTaskId
@@ -3472,19 +3424,17 @@ class Task extends TaskFragment {
info.isFocused = isFocused();
info.isVisible = hasVisibleChildren();
info.isSleeping = shouldSleepActivities();
- ActivityRecord topRecord = getTopNonFinishingActivity();
- info.mTopActivityLocusId = topRecord != null ? topRecord.getLocusId() : null;
}
@Nullable PictureInPictureParams getPictureInPictureParams() {
- return getPictureInPictureParams(getTopMostTask());
+ final Task topTask = getTopMostTask();
+ if (topTask == null) return null;
+ return getPictureInPictureParams(topTask.getTopMostActivity());
}
- private @Nullable PictureInPictureParams getPictureInPictureParams(Task top) {
- if (top == null) return null;
- final ActivityRecord topMostActivity = top.getTopMostActivity();
- return (topMostActivity == null || topMostActivity.pictureInPictureArgs.empty())
- ? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
+ private static @Nullable PictureInPictureParams getPictureInPictureParams(ActivityRecord top) {
+ return (top == null || top.pictureInPictureArgs.empty())
+ ? null : new PictureInPictureParams(top.pictureInPictureArgs);
}
private boolean shouldDockBigOverlays() {
@@ -3718,42 +3668,6 @@ class Task extends TaskFragment {
return toString();
}
- /** @see #getNumRunningActivities(TaskActivitiesReport) */
- static class TaskActivitiesReport implements Consumer<ActivityRecord> {
- int numRunning;
- int numActivities;
- ActivityRecord top;
- ActivityRecord base;
-
- void reset() {
- numRunning = numActivities = 0;
- top = base = null;
- }
-
- @Override
- public void accept(ActivityRecord r) {
- if (r.finishing) {
- return;
- }
-
- base = r;
-
- // Increment the total number of non-finishing activities
- numActivities++;
-
- if (top == null || (top.isState(INITIALIZING))) {
- top = r;
- // Reset the number of running activities until we hit the first non-initializing
- // activity
- numRunning = 0;
- }
- if (r.attachedToProcess()) {
- // Increment the number of actually running activities
- numRunning++;
- }
- }
- }
-
/**
* Saves this {@link Task} to XML using given serializer.
*/
@@ -4652,22 +4566,12 @@ class Task extends TaskFragment {
moveToFront(reason, null);
}
- void moveToFront(String reason, Task task) {
- if (mMoveAdjacentTogether && getAdjacentTaskFragment() != null) {
- final Task adjacentTask = getAdjacentTaskFragment().asTask();
- if (adjacentTask != null) {
- adjacentTask.moveToFrontInner(reason + " adjacentTaskToTop", null /* task */);
- }
- }
- moveToFrontInner(reason, task);
- }
-
/**
* @param reason The reason for moving the root task to the front.
* @param task If non-null, the task will be moved to the top of the root task.
*/
@VisibleForTesting
- void moveToFrontInner(String reason, Task task) {
+ void moveToFront(String reason, Task task) {
if (!isAttached()) {
return;
}
@@ -5581,23 +5485,10 @@ class Task extends TaskFragment {
}
}
- /**
- * Worker method for rearranging history task. Implements the function of moving all
- * activities for a specific task (gathering them if disjoint) into a single group at the
- * bottom of the root task.
- *
- * If a watcher is installed, the action is preflighted and the watcher has an opportunity
- * to premeptively cancel the move.
- *
- * @param tr The task to collect and move to the bottom.
- * @return Returns true if the move completed, false if not.
- */
- boolean moveTaskToBack(Task tr) {
- Slog.i(TAG, "moveTaskToBack: " + tr);
-
+ private boolean canMoveTaskToBack(Task task) {
// In LockTask mode, moving a locked task to the back of the root task may expose unlocked
// ones. Therefore we need to check if this operation is allowed.
- if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) {
+ if (!mAtmService.getLockTaskController().canMoveTaskToBack(task)) {
return false;
}
@@ -5605,7 +5496,7 @@ class Task extends TaskFragment {
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) {
- ActivityRecord next = topRunningActivity(null, tr.mTaskId);
+ ActivityRecord next = topRunningActivity(null, task.mTaskId);
if (next == null) {
next = topRunningActivity(null, INVALID_TASK_ID);
}
@@ -5623,15 +5514,70 @@ class Task extends TaskFragment {
}
}
}
+ return true;
+ }
+
+ /**
+ * Worker method for rearranging history task. Implements the function of moving all
+ * activities for a specific task (gathering them if disjoint) into a single group at the
+ * bottom of the root task.
+ *
+ * If a watcher is installed, the action is preflighted and the watcher has an opportunity
+ * to premeptively cancel the move.
+ *
+ * If this is a pinned task, it will be removed instead of rearranged.
+ *
+ * @param tr The task to collect and move to the bottom.
+ * @return Returns true if the move completed, false if not.
+ */
+ boolean moveTaskToBack(Task tr) {
+ Slog.i(TAG, "moveTaskToBack: " + tr);
+
+ if (!canMoveTaskToBack(tr)) return false;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ tr.mTaskId);
- // Skip the transition for pinned task.
- if (!inPinnedWindowingMode()) {
- mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr);
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */,
+ mTransitionController, mWmService.mSyncEngine);
+ // Guarantee that this gets its own transition by queueing on SyncEngine
+ if (mWmService.mSyncEngine.hasActiveSync()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Creating Pending Move-to-back: %s", transition);
+ mWmService.mSyncEngine.queueSyncSet(
+ () -> mTransitionController.moveToCollecting(transition),
+ () -> {
+ mTransitionController.requestStartTransition(transition, tr,
+ null /* remoteTransition */, null /* displayChange */);
+ // Need to check again since this happens later and the system might
+ // be in a different state.
+ if (!canMoveTaskToBack(tr)) {
+ Slog.e(TAG, "Failed to move task to back after saying we could: "
+ + tr.mTaskId);
+ transition.abort();
+ return;
+ }
+ moveTaskToBackInner(tr);
+ });
+ } else {
+ mTransitionController.moveToCollecting(transition);
+ mTransitionController.requestStartTransition(transition, tr,
+ null /* remoteTransition */, null /* displayChange */);
+ moveTaskToBackInner(tr);
+ }
+ } else {
+ // Skip the transition for pinned task.
+ if (!inPinnedWindowingMode()) {
+ mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK);
+ }
+ moveTaskToBackInner(tr);
}
- moveToBack("moveTaskToBackLocked", tr);
+ return true;
+ }
+
+ private boolean moveTaskToBackInner(@NonNull Task task) {
+ moveToBack("moveTaskToBackInner", task);
if (inPinnedWindowingMode()) {
mTaskSupervisor.removeRootTask(this);
@@ -6028,8 +5974,13 @@ class Task extends TaskFragment {
mLastRecentsAnimationTransaction = null;
mLastRecentsAnimationOverlay = null;
// reset also the crop and transform introduced by mLastRecentsAnimationTransaction
- getPendingTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9])
+ resetSurfaceControlTransforms();
+ }
+
+ void resetSurfaceControlTransforms() {
+ getSyncTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9])
.setWindowCrop(mSurfaceControl, null)
+ .setShadowRadius(mSurfaceControl, 0)
.setCornerRadius(mSurfaceControl, 0);
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index dd1b50fc5e0b..d9835722130f 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -29,7 +29,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
@@ -91,20 +90,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
*/
private int mColorLayerCounter = 0;
- /**
- * Given that the split-screen divider does not have an AppWindowToken, it
- * will have to live inside of a "NonAppWindowContainer". However, in visual Z order
- * it will need to be interleaved with some of our children, appearing on top of
- * both docked root tasks but underneath any assistant root tasks.
- *
- * To solve this problem we have this anchor control, which will always exist so
- * we can always assign it the correct value in our {@link #assignChildLayers}.
- * Likewise since it always exists, we can always
- * assign the divider a layer relative to it. This way we prevent linking lifecycle
- * events between tasks and the divider window.
- */
- private SurfaceControl mSplitScreenDividerAnchor;
-
// Cached reference to some special tasks we tend to get a lot so we don't need to loop
// through the list to find them.
private Task mRootHomeTask;
@@ -422,8 +407,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// wasContained} restricts the preferred root task is set only when moving an existing
// root task to top instead of adding a new root task that may be too early (e.g. in the
// middle of launching or reparenting).
- if (moveToTop && child.isFocusableAndVisible()) {
- mPreferredTopFocusableRootTask = child;
+ final boolean isTopFocusableTask = moveToTop && child.isTopActivityFocusable();
+ if (isTopFocusableTask) {
+ mPreferredTopFocusableRootTask =
+ child.shouldBeVisible(null /* starting */) ? child : null;
} else if (mPreferredTopFocusableRootTask == child) {
mPreferredTopFocusableRootTask = null;
}
@@ -728,12 +715,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// Place root home tasks to the bottom.
layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer);
layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer);
- // TODO(b/207185041): Remove this divider workaround after we full remove leagacy split and
- // make app pair split only have single root then we can just attach the
- // divider to the single root task in shell.
- layer = Math.max(layer, SPLIT_DIVIDER_LAYER + 1);
adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer);
- t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER);
}
/**
@@ -761,19 +743,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
continue;
}
- final Task childTask = child.asTask();
- final boolean inAdjacentTask = childTask != null
- && child.inMultiWindowMode()
- && childTask.getRootTask().getAdjacentTaskFragment() != null;
-
- if (inAdjacentTask) {
- hasAdjacentTask = true;
- } else if (hasAdjacentTask && startLayer < SPLIT_DIVIDER_LAYER) {
- // Task on top of adjacent tasks should be higher than split divider layer so
- // set it as start.
- startLayer = SPLIT_DIVIDER_LAYER + 1;
- }
-
child.assignLayer(t, startLayer++);
}
@@ -800,31 +769,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return activity != null ? activity.createRemoteAnimationTarget(record) : null;
}
- SurfaceControl getSplitScreenDividerAnchor() {
- return mSplitScreenDividerAnchor;
- }
-
- @Override
- void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- if (getParent() != null) {
- super.onParentChanged(newParent, oldParent, () -> {
- mSplitScreenDividerAnchor = makeChildSurface(null)
- .setName("splitScreenDividerAnchor")
- .setCallsite("TaskDisplayArea.onParentChanged")
- .build();
-
- getSyncTransaction()
- .show(mSplitScreenDividerAnchor);
- });
- } else {
- super.onParentChanged(newParent, oldParent);
- mWmService.mTransactionFactory.get()
- .remove(mSplitScreenDividerAnchor)
- .apply();
- mSplitScreenDividerAnchor = null;
- }
- }
-
void setBackgroundColor(@ColorInt int colorInt) {
setBackgroundColor(colorInt, false /* restore */);
}
@@ -870,12 +814,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
setBackgroundColor(mBackgroundColor, true /* restore */);
}
- if (mSplitScreenDividerAnchor == null) {
- return;
- }
-
- // As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces.
- t.reparent(mSplitScreenDividerAnchor, mSurfaceControl);
reassignLayer(t);
scheduleAnimation();
}
@@ -1898,15 +1836,12 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
task.remove(false /* withTransition */, "removeTaskDisplayArea");
} else {
// Reparent task to corresponding launch root or display area.
- final WindowContainer launchRoot =
- task.supportsSplitScreenWindowingModeInDisplayArea(toDisplayArea)
- ? toDisplayArea.getLaunchRootTask(
+ final WindowContainer launchRoot = toDisplayArea.getLaunchRootTask(
task.getWindowingMode(),
task.getActivityType(),
null /* options */,
null /* sourceTask */,
- 0 /* launchFlags */)
- : null;
+ 0 /* launchFlags */);
task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
// Set the windowing mode to undefined by default to let the root task inherited the
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index eca0fd77fcb9..d77e9b397ef9 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -152,6 +152,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final RootWindowContainer mRootWindowContainer;
private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
+ // TODO(b/233177466): Move mMinWidth and mMinHeight to Task and remove usages in TaskFragment
/**
* Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
* should use the default minimal width.
@@ -174,14 +175,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
private TaskFragment mAdjacentTaskFragment;
/**
- * Whether to move adjacent task fragment together when re-positioning.
- *
- * @see #mAdjacentTaskFragment
- */
- // TODO(b/207185041): Remove this once having a single-top root for split screen.
- boolean mMoveAdjacentTogether;
-
- /**
* Prevents duplicate calls to onTaskAppeared.
*/
boolean mTaskFragmentAppearedSent;
@@ -333,15 +326,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return service.mWindowOrganizerController.getTaskFragment(token);
}
- void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment, boolean moveTogether) {
+ void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
if (mAdjacentTaskFragment == taskFragment) {
return;
}
resetAdjacentTaskFragment();
if (taskFragment != null) {
mAdjacentTaskFragment = taskFragment;
- mMoveAdjacentTogether = moveTogether;
- taskFragment.setAdjacentTaskFragment(this, moveTogether);
+ taskFragment.setAdjacentTaskFragment(this);
}
}
@@ -350,11 +342,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
mAdjacentTaskFragment.mAdjacentTaskFragment = null;
mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
- mAdjacentTaskFragment.mMoveAdjacentTogether = false;
}
mAdjacentTaskFragment = null;
mDelayLastActivityRemoval = false;
- mMoveAdjacentTogether = false;
}
void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
@@ -535,6 +525,25 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|| isAllowedToEmbedActivityInTrustedMode(a, uid);
}
+ boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
+ final Rect taskFragBounds = getBounds();
+ final Task task = getTask();
+ // Don't need to check if the bounds match parent Task bounds because the fallback mechanism
+ // is to reparent the Activity to parent if minimum dimensions are not satisfied.
+ if (task == null || taskFragBounds.equals(task.getBounds())) {
+ return false;
+ }
+ final Point minDimensions = activity.getMinDimensions();
+ if (minDimensions == null) {
+ return false;
+ }
+ final int minWidth = minDimensions.x;
+ final int minHeight = minDimensions.y;
+ final boolean smaller = taskFragBounds.width() < minWidth
+ || taskFragBounds.height() < minHeight;
+ return smaller;
+ }
+
/**
* Checks if the organized task fragment is allowed to embed activity in untrusted mode.
*/
@@ -1534,7 +1543,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (prev.attachedToProcess()) {
if (shouldAutoPip) {
boolean didAutoPip = mAtmService.enterPictureInPictureMode(
- prev, prev.pictureInPictureArgs);
+ prev, prev.pictureInPictureArgs, false /* fromClient */);
ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+ "directly: %s, didAutoPip: %b", prev, didAutoPip);
} else {
@@ -1572,8 +1581,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
} else {
prev.schedulePauseTimeout();
- // Unset readiness since we now need to wait until this pause is complete.
- mTransitionController.setReady(this, false /* ready */);
+ // All activities will be stopped when sleeping, don't need to wait for pause.
+ if (!uiSleeping) {
+ // Unset readiness since we now need to wait until this pause is complete.
+ mTransitionController.setReady(this, false /* ready */);
+ }
return true;
}
@@ -1755,7 +1767,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mClearedTaskForReuse = false;
mClearedTaskFragmentForPip = false;
- boolean isAddingActivity = child.asActivityRecord() != null;
+ final ActivityRecord addingActivity = child.asActivityRecord();
+ final boolean isAddingActivity = addingActivity != null;
final Task task = isAddingActivity ? getTask() : null;
// If this task had any activity before we added this one.
@@ -1780,7 +1793,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
}
child.asActivityRecord().inHistory = true;
- task.onDescendantActivityAdded(taskHadActivity, activityType, child.asActivityRecord());
+ task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
}
}
@@ -1866,19 +1879,19 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (!mAtmService.mSupportsMultiWindow) {
return false;
}
- final Task task = getTask();
- if (task == null) {
+ if (tda == null) {
return false;
}
- if (tda == null) {
+ final Task task = getTask();
+ if (task == null) {
return false;
}
- if (!getTask().isResizeable() && !tda.supportsNonResizableMultiWindow()) {
+ if (!task.isResizeable() && !tda.supportsNonResizableMultiWindow()) {
// Not support non-resizable in multi window.
return false;
}
- final ActivityRecord rootActivity = getTask().getRootActivity();
+ final ActivityRecord rootActivity = task.getRootActivity();
return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight,
rootActivity != null ? rootActivity.info : null);
}
@@ -2040,13 +2053,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+ final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density + 0.5f);
inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
: overrideScreenWidthDp;
}
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+ final int overrideScreenHeightDp =
+ (int) (mTmpStableBounds.height() / density + 0.5f);
inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
: overrideScreenHeightDp;
@@ -2065,8 +2079,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
// For floating tasks, calculate the smallest width from the bounds of the
// task, because they should not be affected by insets.
- inOutConfig.smallestScreenWidthDp = (int) (
- Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
+ inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
} else if (isEmbedded()) {
// For embedded TFs, the smallest width should be updated. Otherwise, inherit
// from the parent task would result in applications loaded wrong resource.
@@ -2085,8 +2099,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// For calculating screen layout, we need to use the non-decor inset screen area for the
// calculation for compatibility reasons, i.e. screen area without system bars that
// could never go away in Honeycomb.
- int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
- int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density + 0.5f);
+ int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density + 0.5f);
// Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
// undefined so it can't be used.
if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
@@ -2294,7 +2308,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
TaskFragmentInfo getTaskFragmentInfo() {
List<IBinder> childActivities = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
- final WindowContainer wc = getChildAt(i);
+ final WindowContainer<?> wc = getChildAt(i);
final ActivityRecord ar = wc.asActivityRecord();
if (mTaskFragmentOrganizerUid != INVALID_UID && ar != null
&& ar.info.processName.equals(mTaskFragmentOrganizerProcessName)
@@ -2314,7 +2328,31 @@ class TaskFragment extends WindowContainer<WindowContainer> {
childActivities,
positionInParent,
mClearedTaskForReuse,
- mClearedTaskFragmentForPip);
+ mClearedTaskFragmentForPip,
+ calculateMinDimension());
+ }
+
+ /**
+ * Calculates the minimum dimensions that this TaskFragment can be resized.
+ * @see TaskFragmentInfo#getMinimumWidth()
+ * @see TaskFragmentInfo#getMinimumHeight()
+ */
+ Point calculateMinDimension() {
+ final int[] maxMinWidth = new int[1];
+ final int[] maxMinHeight = new int[1];
+
+ forAllActivities(a -> {
+ if (a.finishing) {
+ return;
+ }
+ final Point minDimensions = a.getMinDimensions();
+ if (minDimensions == null) {
+ return;
+ }
+ maxMinWidth[0] = Math.max(maxMinWidth[0], minDimensions.x);
+ maxMinHeight[0] = Math.max(maxMinHeight[0], minDimensions.y);
+ });
+ return new Point(maxMinWidth[0], maxMinHeight[0]);
}
@Nullable
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 6e84681f0ab5..9da78e1aea3f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -54,10 +54,10 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@@ -319,13 +319,13 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final WindowManagerGlobalLock mGlobalLock;
// List of task organizers by priority
- private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
+ private final ArrayDeque<ITaskOrganizer> mTaskOrganizers = new ArrayDeque<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
// Pending task events due to layout deferred.
private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
// Set of organized tasks (by taskId) that dispatch back pressed to their organizers
- private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
+ private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet<>();
private RunningTaskInfo mTmpTaskInfo;
private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 47c397d12720..03ca4fd49a96 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -41,7 +41,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
import android.util.DisplayMetrics;
@@ -222,8 +221,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragWindowHandle.token = mClientChannel.getToken();
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.ownerPid = Process.myPid();
- mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mDragWindowHandle.ownerUid = WindowManagerService.MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
// When dragging the window around, we do not want to steal focus for the window.
mDragWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f6f9020555d8..84f6104652e3 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -27,6 +27,7 @@ import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -45,6 +46,7 @@ import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
@@ -52,6 +54,8 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
@@ -91,6 +95,7 @@ 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.function.Predicate;
/**
@@ -127,18 +132,27 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
*/
private static final int STATE_ABORT = 3;
+ /**
+ * This transition has finished playing successfully.
+ */
+ private static final int STATE_FINISHED = 4;
+
@IntDef(prefix = { "STATE_" }, value = {
STATE_PENDING,
STATE_COLLECTING,
STATE_STARTED,
STATE_PLAYING,
- STATE_ABORT
+ STATE_ABORT,
+ STATE_FINISHED
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionState {}
final @TransitionType int mType;
private int mSyncId = -1;
+ // Used for tracking a Transition throughout a lifecycle (i.e. from STATE_COLLECTING to
+ // STATE_FINISHED or STATE_ABORT), and should only be used for testing and debugging.
+ private int mDebugId = -1;
private @TransitionFlags int mFlags;
private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
@@ -198,6 +212,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mFlags = flags;
mController = controller;
mSyncEngine = syncEngine;
+
+ controller.mTransitionTracer.logState(this);
}
void addFlag(int flag) {
@@ -210,10 +226,26 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mTransientLaunches = new ArrayMap<>();
}
mTransientLaunches.put(activity, restoreBelow);
+ setTransientLaunchToChanges(activity);
+
+ if (restoreBelow != null) {
+ final ChangeInfo info = mChanges.get(restoreBelow);
+ info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
+ }
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
+ "transient-launch", mSyncId, activity);
}
+ boolean isTransientHide(@NonNull Task task) {
+ if (mTransientLaunches == null) return false;
+ for (int i = 0; i < mTransientLaunches.size(); ++i) {
+ if (mTransientLaunches.valueAt(i) == task) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean isTransientLaunch(@NonNull ActivityRecord activity) {
return mTransientLaunches != null && mTransientLaunches.containsKey(activity);
}
@@ -238,11 +270,35 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
info.mFlags = info.mFlags | ChangeInfo.FLAG_SEAMLESS_ROTATION;
}
+ /**
+ * Only set flag to the parent tasks and activity itself.
+ */
+ private void setTransientLaunchToChanges(@NonNull WindowContainer wc) {
+ for (WindowContainer curr = wc; curr != null && mChanges.containsKey(curr);
+ curr = curr.getParent()) {
+ if (curr.asTask() == null && curr.asActivityRecord() == null) {
+ return;
+ }
+ final ChangeInfo info = mChanges.get(curr);
+ info.mFlags = info.mFlags | ChangeInfo.FLAG_TRANSIENT_LAUNCH;
+ }
+ }
+
+ @TransitionState
+ int getState() {
+ return mState;
+ }
+
@VisibleForTesting
int getSyncId() {
return mSyncId;
}
+ @VisibleForTesting
+ int getDebugId() {
+ return mDebugId;
+ }
+
@TransitionFlags
int getFlags() {
return mFlags;
@@ -255,6 +311,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
mState = STATE_COLLECTING;
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
+ mDebugId = mSyncId;
+
+ mController.mTransitionTracer.logState(this);
}
/**
@@ -272,6 +331,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
mSyncId);
applyReady();
+
+ mController.mTransitionTracer.logState(this);
}
/**
@@ -296,7 +357,12 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
}
if (mParticipants.contains(wc)) return;
- mSyncEngine.addToSyncSet(mSyncId, wc);
+ // Wallpaper is like in a static drawn state unless display may have changes, so exclude
+ // the case to reduce transition latency waiting for the unchanged wallpaper to redraw.
+ final boolean needSyncDraw = !isWallpaper(wc) || mParticipants.contains(wc.mDisplayContent);
+ if (needSyncDraw) {
+ mSyncEngine.addToSyncSet(mSyncId, wc);
+ }
ChangeInfo info = mChanges.get(wc);
if (info == null) {
info = new ChangeInfo(wc);
@@ -419,7 +485,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
for (int i = mTargets.size() - 1; i >= 0; --i) {
final WindowContainer target = mTargets.get(i);
if (target.getParent() != null) {
- final SurfaceControl targetLeash = getLeashSurface(target);
+ final SurfaceControl targetLeash = getLeashSurface(target, null /* t */);
final SurfaceControl origParent = getOrigParentSurface(target);
// Ensure surfaceControls are re-parented back into the hierarchy.
t.reparent(targetLeash, origParent);
@@ -428,14 +494,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
t.setPosition(targetLeash, tmpPos.x, tmpPos.y);
final Rect clipRect;
// No need to clip the display in case seeing the clipped content when during the
- // display rotation.
- if (target.asDisplayContent() != null) {
+ // display rotation. No need to clip activities because they rely on clipping on
+ // task layers.
+ if (target.asDisplayContent() != null || target.asActivityRecord() != null) {
clipRect = null;
- } else if (target.asActivityRecord() != null) {
- // Always use parent bounds of activity because letterbox area (e.g. fixed
- // aspect ratio or size compat mode) should be included.
- clipRect = target.getParent().getRequestedOverrideBounds();
- clipRect.offset(-tmpPos.x, -tmpPos.y);
} else {
clipRect = target.getRequestedOverrideBounds();
clipRect.offset(-tmpPos.x, -tmpPos.y);
@@ -474,6 +536,58 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mCanPipOnFinish = canPipOnFinish;
}
+ private boolean didCommitTransientLaunch() {
+ if (mTransientLaunches == null) return false;
+ for (int j = 0; j < mTransientLaunches.size(); ++j) {
+ if (mTransientLaunches.keyAt(j).isVisibleRequested()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if pip-entry is possible after finishing and enter-pip if it is.
+ *
+ * @return true if we are *guaranteed* to enter-pip. This means we return false if there's
+ * a chance we won't thus legacy-entry (via pause+userLeaving) will return false.
+ */
+ private boolean checkEnterPipOnFinish(@NonNull ActivityRecord ar) {
+ if (!mCanPipOnFinish || !ar.isVisible() || ar.getTask() == null) return false;
+
+ if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (didCommitTransientLaunch()) {
+ // force enable pip-on-task-switch now that we've committed to actually launching
+ // to the transient activity.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ }
+ return mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs,
+ false /* fromClient */);
+ }
+
+ // Legacy pip-entry (not via isAutoEnterEnabled).
+ boolean canPip = ar.getDeferHidingClient();
+ if (!canPip && didCommitTransientLaunch()) {
+ // force enable pip-on-task-switch now that we've committed to actually launching to the
+ // transient activity, and then recalculate whether we can attempt pip.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ canPip = ar.checkEnterPictureInPictureState(
+ "finishTransition", true /* beforeStopping */)
+ && ar.isState(RESUMED);
+ }
+ if (!canPip) return false;
+ try {
+ // Legacy PIP-enter requires pause event with user-leaving.
+ mController.mAtm.mTaskSupervisor.mUserLeaving = true;
+ ar.getTaskFragment().startPausing(false /* uiSleeping */,
+ null /* resuming */, "finishTransition");
+ } finally {
+ mController.mAtm.mTaskSupervisor.mUserLeaving = false;
+ }
+ // Return false anyway because there's no guarantee that the app will enter pip.
+ return false;
+ }
+
/**
* The transition has finished animating and is ready to finalize WM state. This should not
* be called directly; use {@link TransitionController#finishTransition} instead.
@@ -489,7 +603,6 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
// Commit all going-invisible containers
- boolean activitiesWentInvisible = false;
for (int i = 0; i < mParticipants.size(); ++i) {
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
if (ar != null) {
@@ -501,32 +614,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// then doing commitVisibility here would actually be out-of-order and leave the
// activity in a bad state.
if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
- boolean commitVisibility = true;
- if (mCanPipOnFinish && ar.isVisible() && ar.getTask() != null) {
- if (ar.pictureInPictureArgs != null
- && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
- if (mTransientLaunches != null) {
- for (int j = 0; j < mTransientLaunches.size(); ++j) {
- if (mTransientLaunches.keyAt(j).isVisibleRequested()) {
- // force enable pip-on-task-switch now that we've committed
- // to actually launching to the transient activity.
- ar.supportsEnterPipOnTaskSwitch = true;
- break;
- }
- }
- }
- mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs);
- // Avoid commit visibility to false here, or else we will get a sudden
- // "flash" / surface going invisible for a split second.
- commitVisibility = false;
- } else if (ar.getDeferHidingClient()) {
- // Legacy PIP-enter requires pause event with user-leaving.
- mController.mAtm.mTaskSupervisor.mUserLeaving = true;
- ar.getTaskFragment().startPausing(false /* uiSleeping */,
- null /* resuming */, "finishTransition");
- mController.mAtm.mTaskSupervisor.mUserLeaving = false;
- }
- }
+ final boolean commitVisibility = !checkEnterPipOnFinish(ar);
+ // Avoid commit visibility if entering pip or else we will get a sudden
+ // "flash" / surface going invisible for a split second.
if (commitVisibility) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
@@ -540,7 +630,6 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
ar.commitVisibility(false /* visible */, false /* performLayout */,
true /* fromTransition */);
- activitiesWentInvisible = true;
}
}
if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) {
@@ -567,12 +656,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mController.dispatchLegacyAppTransitionFinished(ar);
}
}
- if (activitiesWentInvisible) {
- // Always schedule stop processing when transition finishes because activities don't
- // stop while they are in a transition thus their stop could still be pending.
- mController.mAtm.mTaskSupervisor
- .scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
- }
+ // Always schedule stop processing when transition finishes because activities don't
+ // stop while they are in a transition thus their stop could still be pending.
+ mController.mAtm.mTaskSupervisor
+ .scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
sendRemoteCallback(mClientAnimationFinishCallback);
@@ -614,6 +701,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
dc.removeImeSurfaceImmediately();
dc.handleCompleteDeferredRemoval();
}
+
+ mState = STATE_FINISHED;
+ mController.mTransitionTracer.logState(this);
}
void abort() {
@@ -675,7 +765,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// Resolve the animating targets from the participants
mTargets = calculateTargets(mParticipants, mChanges);
- final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
+ final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges,
+ transaction);
if (mOverrideOptions != null) {
info.setAnimationOptions(mOverrideOptions);
}
@@ -685,8 +776,6 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
handleNonAppWindowsInTransition(dc, mType, mFlags);
- reportStartReasonsToLogger();
-
// The callback is only populated for custom activity-level client animations
sendRemoteCallback(mClientAnimationStartCallback);
@@ -728,6 +817,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
for (int i = mParticipants.size() - 1; i >= 0; --i) {
final WindowContainer wc = mParticipants.valueAt(i);
if (wc.asWindowToken() == null || !wc.isVisibleRequested()) continue;
+ // don't include transient launches, though, since those are only temporarily visible.
+ if (mTransientLaunches != null && wc.asActivityRecord() != null
+ && mTransientLaunches.containsKey(wc.asActivityRecord())) continue;
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
}
@@ -775,6 +867,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
mSyncId = -1;
mOverrideOptions = null;
+
+ reportStartReasonsToLogger();
}
/**
@@ -987,11 +1081,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
for (int i = mParticipants.size() - 1; i >= 0; --i) {
ActivityRecord r = mParticipants.valueAt(i).asActivityRecord();
if (r == null || !r.mVisibleRequested) continue;
+ int transitionReason = APP_TRANSITION_WINDOWS_DRAWN;
// At this point, r is "ready", but if it's not "ALL ready" then it is probably only
// ready due to starting-window.
- reasons.put(r, (r.mStartingData instanceof SplashScreenStartingData
- && !r.mLastAllReadyAtSync)
- ? APP_TRANSITION_SPLASH_SCREEN : APP_TRANSITION_WINDOWS_DRAWN);
+ if (r.mStartingData instanceof SplashScreenStartingData && !r.mLastAllReadyAtSync) {
+ transitionReason = APP_TRANSITION_SPLASH_SCREEN;
+ } else if (r.isActivityTypeHomeOrRecents() && isTransientLaunch(r)) {
+ transitionReason = APP_TRANSITION_RECENTS_ANIM;
+ }
+ reasons.put(r, transitionReason);
}
mController.mAtm.mTaskSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
reasons);
@@ -1020,6 +1118,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return wc.asWallpaperToken() != null;
}
+ private static boolean isInputMethod(WindowContainer wc) {
+ return wc.getWindowType() == TYPE_INPUT_METHOD;
+ }
+
private static boolean occludesKeyguard(WindowContainer wc) {
final ActivityRecord ar = wc.asActivityRecord();
if (ar != null) {
@@ -1226,8 +1328,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
}
- /** Gets the leash surface for a window container */
- private static SurfaceControl getLeashSurface(WindowContainer wc) {
+ /**
+ * Gets the leash surface for a window container.
+ * @param t a transaction to create leashes on when necessary (fixed rotation at token-level).
+ * If t is null, then this will not create any leashes, just use one if it is there --
+ * this is relevant for building the finishTransaction since it needs to match the
+ * start state and not erroneously create a leash of its own.
+ */
+ private static SurfaceControl getLeashSurface(WindowContainer wc,
+ @Nullable SurfaceControl.Transaction t) {
final DisplayContent asDC = wc.asDisplayContent();
if (asDC != null) {
// DisplayContent is the "root", so we use the windowing layer instead to avoid
@@ -1239,7 +1348,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (asToken != null) {
// WindowTokens can have a fixed-rotation applied to them. In the current
// implementation this fact is hidden from the player, so we must create a leash.
- final SurfaceControl leash = asToken.getOrCreateFixedRotationLeash();
+ final SurfaceControl leash = t != null ? asToken.getOrCreateFixedRotationLeash(t)
+ : asToken.getFixedRotationLeash();
if (leash != null) return leash;
}
}
@@ -1268,12 +1378,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
* Construct a TransitionInfo object from a set of targets and changes. Also populates the
* root surface.
* @param sortedTargets The targets sorted by z-order from top (index 0) to bottom.
+ * @param startT The start transaction - used to set-up new leashes.
*/
@VisibleForTesting
@NonNull
static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
ArrayList<WindowContainer> sortedTargets,
- ArrayMap<WindowContainer, ChangeInfo> changes) {
+ ArrayMap<WindowContainer, ChangeInfo> changes,
+ @Nullable SurfaceControl.Transaction startT) {
final TransitionInfo out = new TransitionInfo(type, flags);
WindowContainer<?> topApp = null;
@@ -1311,10 +1423,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
"Transition Root: " + leashReference.getName()).build();
- SurfaceControl.Transaction t = ancestor.mWmService.mTransactionFactory.get();
- t.setLayer(rootLeash, leashReference.getLastLayer());
- t.apply();
- t.close();
+ startT.setLayer(rootLeash, leashReference.getLastLayer());
out.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
@@ -1324,7 +1433,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final ChangeInfo info = changes.get(target);
final TransitionInfo.Change change = new TransitionInfo.Change(
target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
- : null, getLeashSurface(target));
+ : null, getLeashSurface(target, startT));
// TODO(shell-transitions): Use leash for non-organized windows.
if (info.mParent != null) {
change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
@@ -1497,10 +1606,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
* seamless rotation. This is currently only used by DisplayContent during fixed-rotation.
*/
private static final int FLAG_SEAMLESS_ROTATION = 1;
+ private static final int FLAG_TRANSIENT_LAUNCH = 2;
+ private static final int FLAG_ABOVE_TRANSIENT_LAUNCH = 4;
@IntDef(prefix = { "FLAG_" }, value = {
FLAG_NONE,
- FLAG_SEAMLESS_ROTATION
+ FLAG_SEAMLESS_ROTATION,
+ FLAG_TRANSIENT_LAUNCH,
+ FLAG_ABOVE_TRANSIENT_LAUNCH
})
@Retention(RetentionPolicy.SOURCE)
@interface Flag {}
@@ -1537,6 +1650,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
boolean hasChanged(@NonNull WindowContainer newState) {
+ // the task including transient launch must promote to root task
+ if ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0
+ || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
+ return true;
+ }
// If it's invisible and hasn't changed visibility, always return false since even if
// something changed, it wouldn't be a visible change.
final boolean currVisible = newState.isVisibleRequested();
@@ -1552,6 +1670,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
@TransitionInfo.TransitionMode
int getTransitMode(@NonNull WindowContainer wc) {
+ if ((mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
+ return TRANSIT_CLOSE;
+ }
final boolean nowVisible = wc.isVisibleRequested();
if (nowVisible == mVisible) {
return TRANSIT_CHANGE;
@@ -1602,6 +1723,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (isWallpaper(wc)) {
flags |= FLAG_IS_WALLPAPER;
}
+ if (isInputMethod(wc)) {
+ flags |= FLAG_IS_INPUT_METHOD;
+ }
if (occludesKeyguard(wc)) {
flags |= FLAG_OCCLUDES_KEYGUARD;
}
@@ -1610,6 +1734,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
/**
+ * This transition will be considered not-ready until a corresponding call to
+ * {@link #continueTransitionReady}
+ */
+ void deferTransitionReady() {
+ ++mReadyTracker.mDeferReadyDepth;
+ }
+
+ /** This undoes one call to {@link #deferTransitionReady}. */
+ void continueTransitionReady() {
+ --mReadyTracker.mDeferReadyDepth;
+ }
+
+ /**
* The transition sync mechanism has 2 parts:
* 1. Whether all WM operations for a particular transition are "ready" (eg. did the app
* launch or stop or get a new configuration?).
@@ -1639,6 +1776,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
private boolean mReadyOverride = false;
/**
+ * When non-zero, this transition is forced not-ready (even over setAllReady()). Use this
+ * (via deferTransitionReady/continueTransitionReady) for situations where we want to do
+ * bulk operations which could trigger surface-placement but the existing ready-state
+ * isn't known.
+ */
+ private int mDeferReadyDepth = 0;
+
+ /**
* Adds a ready-group. Any setReady calls in this subtree will be tracked together. For
* now these are only DisplayContents.
*/
@@ -1678,8 +1823,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
/** @return true if all tracked subtrees are ready. */
boolean allReady() {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
- + "override=%b states=[%s]", mUsed, mReadyOverride, groupsToString());
+ + "override=%b defer=%d states=[%s]", mUsed, mReadyOverride, mDeferReadyDepth,
+ groupsToString());
+ // If the readiness has never been touched, mUsed will be false. We never want to
+ // consider a transition ready if nothing has been reported on it.
if (!mUsed) return false;
+ // If we are deferring readiness, we never report ready. This is usually temporary.
+ if (mDeferReadyDepth > 0) return false;
+ // Next check all the ready groups to see if they are ready. We can short-cut this if
+ // ready-override is set (which is treated as "everything is marked ready").
if (mReadyOverride) return true;
for (int i = mReadyGroups.size() - 1; i >= 0; --i) {
final WindowContainer wc = mReadyGroups.keyAt(i);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c1c390eea932..6d31e937984e 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -75,6 +75,7 @@ class TransitionController {
private ITransitionPlayer mTransitionPlayer;
final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter();
+ final TransitionTracer mTransitionTracer;
private IApplicationThread mTransitionPlayerThread;
final ActivityTaskManagerService mAtm;
@@ -100,10 +101,12 @@ class TransitionController {
final StatusBarManagerInternal mStatusBar;
TransitionController(ActivityTaskManagerService atm,
- TaskSnapshotController taskSnapshotController) {
+ TaskSnapshotController taskSnapshotController,
+ TransitionTracer transitionTracer) {
mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
mTaskSnapshotController = taskSnapshotController;
+ mTransitionTracer = transitionTracer;
mTransitionPlayerDeath = () -> {
synchronized (mAtm.mGlobalLock) {
// Clean-up/finish any playing transitions.
@@ -207,6 +210,18 @@ class TransitionController {
}
/**
+ * @return {@code true} if transition is actively collecting changes and `wc` is one of them
+ * or a descendant of one of them. {@code false} once playing.
+ */
+ boolean inCollectingTransition(@NonNull WindowContainer wc) {
+ if (!isCollecting()) return false;
+ for (WindowContainer p = wc; p != null; p = p.getParent()) {
+ if (mCollectingTransition.mParticipants.contains(p)) return true;
+ }
+ return false;
+ }
+
+ /**
* @return {@code true} if transition is actively playing. This is not necessarily {@code true}
* during collection.
*/
@@ -214,6 +229,18 @@ class TransitionController {
return !mPlayingTransitions.isEmpty();
}
+ /**
+ * @return {@code true} if one of the playing transitions contains `wc`.
+ */
+ boolean inPlayingTransition(@NonNull WindowContainer wc) {
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ for (WindowContainer p = wc; p != null; p = p.getParent()) {
+ if (mPlayingTransitions.get(i).mParticipants.contains(p)) return true;
+ }
+ }
+ return false;
+ }
+
/** @return {@code true} if a transition is running */
boolean inTransition() {
// TODO(shell-transitions): eventually properly support multiple
@@ -222,19 +249,7 @@ class TransitionController {
/** @return {@code true} if a transition is running in a participant subtree of wc */
boolean inTransition(@NonNull WindowContainer wc) {
- if (isCollecting()) {
- for (WindowContainer p = wc; p != null; p = p.getParent()) {
- if (isCollecting(p)) return true;
- }
- }
- for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
- for (WindowContainer p = wc; p != null; p = p.getParent()) {
- if (mPlayingTransitions.get(i).mParticipants.contains(p)) {
- return true;
- }
- }
- }
- return false;
+ return inCollectingTransition(wc) || inPlayingTransition(wc);
}
boolean inRecentsTransition(@NonNull WindowContainer wc) {
@@ -270,6 +285,16 @@ class TransitionController {
return false;
}
+ boolean isTransientHide(@NonNull Task task) {
+ if (mCollectingTransition != null && mCollectingTransition.isTransientHide(task)) {
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (mPlayingTransitions.get(i).isTransientHide(task)) return true;
+ }
+ return false;
+ }
+
/**
* @return {@code true} if {@param ar} is part of a transient-launch activity in an active
* transition.
@@ -455,6 +480,24 @@ class TransitionController {
setReady(wc, true);
}
+ /** @see Transition#deferTransitionReady */
+ void deferTransitionReady() {
+ if (!isShellTransitionsEnabled()) return;
+ if (mCollectingTransition == null) {
+ throw new IllegalStateException("No collecting transition to defer readiness for.");
+ }
+ mCollectingTransition.deferTransitionReady();
+ }
+
+ /** @see Transition#continueTransitionReady */
+ void continueTransitionReady() {
+ if (!isShellTransitionsEnabled()) return;
+ if (mCollectingTransition == null) {
+ throw new IllegalStateException("No collecting transition to defer readiness for.");
+ }
+ mCollectingTransition.continueTransitionReady();
+ }
+
/** @see Transition#finishTransition */
void finishTransition(@NonNull IBinder token) {
// It is usually a no-op but make sure that the metric consumer is removed.
@@ -484,6 +527,7 @@ class TransitionController {
setAnimationRunning(true /* running */);
}
mPlayingTransitions.add(transition);
+ mTransitionTracer.logState(transition);
}
private void setAnimationRunning(boolean running) {
@@ -502,6 +546,7 @@ class TransitionController {
}
transition.abort();
mCollectingTransition = null;
+ mTransitionTracer.logState(transition);
}
/**
@@ -526,6 +571,12 @@ class TransitionController {
}
}
+ /** @see Transition#setCanPipOnFinish */
+ void setCanPipOnFinish(boolean canPipOnFinish) {
+ if (mCollectingTransition == null) return;
+ mCollectingTransition.setCanPipOnFinish(canPipOnFinish);
+ }
+
void legacyDetachNavigationBarFromApp(@NonNull IBinder token) {
final Transition transition = Transition.fromBinder(token);
if (transition == null || !mPlayingTransitions.contains(transition)) {
diff --git a/services/core/java/com/android/server/wm/TransitionTracer.java b/services/core/java/com/android/server/wm/TransitionTracer.java
new file mode 100644
index 000000000000..192b9abc62a7
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TransitionTracer.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.os.Build.IS_USER;
+
+import static com.android.server.wm.shell.ChangeInfo.CHANGE_FLAGS;
+import static com.android.server.wm.shell.ChangeInfo.HAS_CHANGED;
+import static com.android.server.wm.shell.ChangeInfo.TRANSIT_MODE;
+import static com.android.server.wm.shell.ChangeInfo.WINDOW_IDENTIFIER;
+import static com.android.server.wm.shell.Transition.CHANGE;
+import static com.android.server.wm.shell.Transition.FLAGS;
+import static com.android.server.wm.shell.Transition.ID;
+import static com.android.server.wm.shell.Transition.STATE;
+import static com.android.server.wm.shell.Transition.TIMESTAMP;
+import static com.android.server.wm.shell.Transition.TRANSITION_TYPE;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.server.wm.shell.TransitionTraceProto.TRANSITION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.TraceBuffer;
+import com.android.server.wm.Transition.ChangeInfo;
+import com.android.server.wm.shell.TransitionTraceProto;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Helper class to collect and dump transition traces.
+ */
+public class TransitionTracer {
+
+ private static final String LOG_TAG = "TransitionTracer";
+
+ /**
+ * Maximum buffer size, currently defined as 5 MB
+ */
+ private static final int BUFFER_CAPACITY = 5120 * 1024; // 5 MB
+ static final String WINSCOPE_EXT = ".winscope";
+ private static final String TRACE_FILE = "/data/misc/wmtrace/transition_trace" + WINSCOPE_EXT;
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final TransitionTraceBuffer mTraceBuffer = new TransitionTraceBuffer();
+
+ private final Object mEnabledLock = new Object();
+ private volatile boolean mEnabled = false;
+
+ private long mTraceStartTimestamp;
+
+ private class TransitionTraceBuffer {
+ private final TraceBuffer mBuffer = new TraceBuffer(BUFFER_CAPACITY);
+
+ private void pushTransitionState(Transition transition) {
+ final ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long transitionEntryToken = outputStream.start(TRANSITION);
+
+ outputStream.write(ID, transition.getDebugId());
+ outputStream.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+ outputStream.write(TRANSITION_TYPE, transition.mType);
+ outputStream.write(STATE, transition.getState());
+ outputStream.write(FLAGS, transition.getFlags());
+
+ for (int i = 0; i < transition.mChanges.size(); ++i) {
+ final WindowContainer window = transition.mChanges.keyAt(i);
+ final ChangeInfo changeInfo = transition.mChanges.valueAt(i);
+ writeChange(outputStream, window, changeInfo);
+ }
+
+ outputStream.end(transitionEntryToken);
+
+ mBuffer.add(outputStream);
+ }
+
+ private void writeChange(ProtoOutputStream outputStream, WindowContainer window,
+ ChangeInfo changeInfo) {
+ Trace.beginSection("TransitionProto#addChange");
+ final long changeEntryToken = outputStream.start(CHANGE);
+
+ final int transitMode = changeInfo.getTransitMode(window);
+ final boolean hasChanged = changeInfo.hasChanged(window);
+ final int changeFlags = changeInfo.getChangeFlags(window);
+
+ outputStream.write(TRANSIT_MODE, transitMode);
+ outputStream.write(HAS_CHANGED, hasChanged);
+ outputStream.write(CHANGE_FLAGS, changeFlags);
+ window.writeIdentifierToProto(outputStream, WINDOW_IDENTIFIER);
+
+ outputStream.end(changeEntryToken);
+ Trace.endSection();
+ }
+
+ public void writeToFile(File file, ProtoOutputStream proto) throws IOException {
+ mBuffer.writeTraceToFile(file, proto);
+ }
+
+ public void reset() {
+ mBuffer.resetBuffer();
+ }
+ }
+
+ /**
+ * Records the current state of a transition in the transition trace (if it is running).
+ * @param transition the transition that we want to record the state of.
+ */
+ public void logState(com.android.server.wm.Transition transition) {
+ if (!mEnabled) {
+ return;
+ }
+
+ Log.d(LOG_TAG, "Logging state of transition " + transition);
+ mTraceBuffer.pushTransitionState(transition);
+ }
+
+ /**
+ * Starts collecting transitions for the trace.
+ * If called while a trace is already running, this will reset the trace.
+ */
+ public void startTrace(@Nullable PrintWriter pw) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("TransitionTracer#startTrace");
+ LogAndPrintln.i(pw, "Starting shell transition trace.");
+ synchronized (mEnabledLock) {
+ mTraceStartTimestamp = SystemClock.elapsedRealtime();
+ mEnabled = true;
+ mTraceBuffer.reset();
+ }
+ Trace.endSection();
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ *
+ * Dumps the trace to @link{TRACE_FILE}.
+ */
+ public void stopTrace(@Nullable PrintWriter pw) {
+ stopTrace(pw, new File(TRACE_FILE));
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ * @param outputFile The file to dump the transition trace to.
+ */
+ public void stopTrace(@Nullable PrintWriter pw, File outputFile) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("TransitionTracer#stopTrace");
+ LogAndPrintln.i(pw, "Stopping shell transition trace.");
+ synchronized (mEnabledLock) {
+ if (!mEnabled) {
+ LogAndPrintln.e(pw,
+ "Error: Tracing can't be stopped because it hasn't been started.");
+ return;
+ }
+
+ mEnabled = false;
+ writeTraceToFileLocked(pw, outputFile);
+ }
+ Trace.endSection();
+ }
+
+ boolean isEnabled() {
+ return mEnabled;
+ }
+
+ private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
+ Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.write(TransitionTraceProto.TIMESTAMP, mTraceStartTimestamp);
+ int pid = android.os.Process.myPid();
+ LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
+ + " from process " + pid);
+ mTraceBuffer.writeToFile(file, proto);
+ } catch (IOException e) {
+ LogAndPrintln.e(pw, "Unable to write buffer to file", e);
+ }
+ Trace.endSection();
+ }
+
+ private static class LogAndPrintln {
+ private static void i(@Nullable PrintWriter pw, String msg) {
+ Log.i(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg) {
+ Log.e(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println("ERROR: " + msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg, @NonNull Exception e) {
+ Log.e(LOG_TAG, msg, e);
+ if (pw != null) {
+ pw.println("ERROR: " + msg + " ::\n " + e);
+ pw.flush();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 5e963cc5ae8e..41c1e793dd90 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -69,6 +69,10 @@ class UnknownAppVisibilityController {
return mUnknownApps.isEmpty();
}
+ boolean isVisibilityUnknown(ActivityRecord r) {
+ return mUnknownApps.containsKey(r);
+ }
+
void clear() {
mUnknownApps.clear();
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index a32a6087a04d..483f51a1c0f5 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -188,7 +188,8 @@ class WallpaperController {
&& animatingContainer.getAnimation().getShowWallpaper();
final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
final boolean isRecentsTransitionTarget = (recentsAnimationController != null
- && recentsAnimationController.isWallpaperVisible(w));
+ && recentsAnimationController.isWallpaperVisible(w))
+ || w.mTransitionController.isTransientHide(w.getTask());
if (isRecentsTransitionTarget) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
mFindResults.setWallpaperTarget(w);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index f9d19e22ddc7..af179941087e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -620,6 +620,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
onSurfaceShown(getSyncTransaction());
updateSurfacePositionNonOrganized();
+ if (mLastMagnificationSpec != null) {
+ applyMagnificationSpec(getSyncTransaction(), mLastMagnificationSpec);
+ }
}
/**
@@ -3012,7 +3015,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
- if (isTaskTransitOld(transit)) {
+ if (isTaskTransitOld(transit) && getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
// TODO: Remove when we migrate to shell (b/202383002)
if (mWmService.mTaskTransitionSpec != null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index 9b6f4d947694..b000a9841d06 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -33,7 +33,6 @@ import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.HardwareBuffer;
-import android.os.Process;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
@@ -91,7 +90,7 @@ class WindowContainerThumbnail implements Animatable {
.setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
.setMetadata(METADATA_WINDOW_TYPE, mWindowContainer.getWindowingMode())
- .setMetadata(METADATA_OWNER_UID, Process.myUid())
+ .setMetadata(METADATA_OWNER_UID, WindowManagerService.MY_UID)
.setCallsite("WindowContainerThumbnail")
.build();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 902218621cd0..a01902b90a71 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -238,10 +238,10 @@ import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.ICrossWindowBlurEnabledListener;
+import android.view.IDisplayChangeWindowController;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
-import android.view.IDisplayWindowRotationController;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedTaskListener;
@@ -397,9 +397,8 @@ public class WindowManagerService extends IWindowManager.Stub
private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
- // Used to indicate that if there is already a transition set, it should be preserved when
- // trying to apply a new one.
- private static final boolean ALWAYS_KEEP_CURRENT = true;
+ static final int MY_PID = myPid();
+ static final int MY_UID = myUid();
static final int LOGTAG_INPUT_FOCUS = 62001;
@@ -460,6 +459,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowManagerConstants mConstants;
final WindowTracing mWindowTracing;
+ final TransitionTracer mTransitionTracer;
private final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider;
@@ -682,9 +682,9 @@ public class WindowManagerService extends IWindowManager.Stub
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
new WallpaperVisibilityListeners();
- IDisplayWindowRotationController mDisplayRotationController = null;
- private final DeathRecipient mDisplayRotationControllerDeath =
- () -> mDisplayRotationController = null;
+ IDisplayChangeWindowController mDisplayChangeController = null;
+ private final DeathRecipient mDisplayChangeControllerDeath =
+ () -> mDisplayChangeController = null;
final DisplayWindowListenerController mDisplayNotificationController;
final TaskSystemBarsListenerController mTaskSystemBarsListenerController;
@@ -1057,17 +1057,11 @@ public class WindowManagerService extends IWindowManager.Stub
// logical displays.
final PossibleDisplayInfoMapper mPossibleDisplayInfoMapper;
- // If true, only the core apps and services are being launched because the device
- // is in a special boot mode, such as being encrypted or waiting for a decryption password.
- // For example, when this flag is true, there will be no wallpaper service.
- final boolean mOnlyCore;
-
static WindowManagerThreadPriorityBooster sThreadPriorityBooster =
new WindowManagerThreadPriorityBooster();
Function<SurfaceSession, SurfaceControl.Builder> mSurfaceControlFactory;
Supplier<SurfaceControl.Transaction> mTransactionFactory;
- final Supplier<Surface> mSurfaceFactory;
private final SurfaceControl.Transaction mTransaction;
@@ -1147,11 +1141,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
+ final boolean showBootMsgs, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
- return main(context, im, showBootMsgs, onlyCore, policy, atm,
- new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
- SurfaceControl.Builder::new);
+ return main(context, im, showBootMsgs, policy, atm, new DisplayWindowSettingsProvider(),
+ SurfaceControl.Transaction::new, SurfaceControl.Builder::new);
}
/**
@@ -1160,15 +1153,14 @@ public class WindowManagerService extends IWindowManager.Stub
*/
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, DisplayWindowSettingsProvider
- displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<Surface> surfaceFactory,
+ final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
+ DisplayWindowSettingsProvider displayWindowSettingsProvider,
+ Supplier<SurfaceControl.Transaction> transactionFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
- wms[0] = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
- atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
+ wms[0] = new WindowManagerService(context, im, showBootMsgs, policy, atm,
+ displayWindowSettingsProvider, transactionFactory,
surfaceControlFactory), 0);
return wms[0];
}
@@ -1178,7 +1170,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
- mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
+ mPolicy.init(mContext, WindowManagerService.this);
}
}, 0);
}
@@ -1190,10 +1182,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
private WindowManagerService(Context context, InputManagerService inputManager,
- boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, DisplayWindowSettingsProvider
- displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<Surface> surfaceFactory,
+ boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
+ DisplayWindowSettingsProvider displayWindowSettingsProvider,
+ Supplier<SurfaceControl.Transaction> transactionFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
@@ -1201,15 +1192,13 @@ public class WindowManagerService extends IWindowManager.Stub
mContext = context;
mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mAllowBootMessages = showBootMsgs;
- mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mHasPermanentDpad = context.getResources().getBoolean(
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
- inputManager.setInTouchMode(
- mInTouchMode, myPid(), myUid(), /* hasPermission = */ true);
+ inputManager.setInTouchMode(mInTouchMode, MY_PID, MY_UID, true /* hasPermission */);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
@@ -1233,7 +1222,6 @@ public class WindowManagerService extends IWindowManager.Stub
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
- mSurfaceFactory = surfaceFactory;
mTransaction = mTransactionFactory.get();
mPolicy = policy;
@@ -1251,6 +1239,7 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
Choreographer.getInstance());
+ mTransitionTracer = new TransitionTracer();
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -2704,7 +2693,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean checkCallingPermission(String permission, String func, boolean printLog) {
- if (Binder.getCallingPid() == myPid()) {
+ if (Binder.getCallingPid() == MY_PID) {
return true;
}
@@ -2864,7 +2853,7 @@ public class WindowManagerService extends IWindowManager.Stub
// registration in DisplayContent#onParentChanged at DisplayContent initialization.
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
- if (Binder.getCallingPid() != myPid()) {
+ if (Binder.getCallingPid() != MY_PID) {
throw new WindowManager.InvalidDisplayException("attachToDisplayContent: "
+ "trying to attach to a non-existing display:" + displayId);
}
@@ -3658,8 +3647,8 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: mDisplayEnabled=%b"
+ " mForceDisplayEnabled=%b" + " mShowingBootMessages=%b"
- + " mSystemBooted=%b mOnlyCore=%b. %s", mDisplayEnabled,
- mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, mOnlyCore,
+ + " mSystemBooted=%b. %s", mDisplayEnabled,
+ mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
new RuntimeException("here").fillInStackTrace());
if (mDisplayEnabled) {
return;
@@ -3707,11 +3696,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
try {
- IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
+ // TODO(b/221898546): remove the following and convert to jni
+ IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlingerAIDL");
if (surfaceFlinger != null) {
ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ data.writeInterfaceToken("android.gui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
@@ -4260,12 +4250,13 @@ public class WindowManagerService extends IWindowManager.Stub
.notifyOnActivityRotation(displayContent.mDisplayId);
}
- final boolean pendingRemoteRotation = rotationChanged
- && (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
+ final boolean pendingRemoteDisplayChange = rotationChanged
+ && (displayContent.mRemoteDisplayChangeController
+ .isWaitingForRemoteDisplayChange()
|| displayContent.mTransitionController.isCollecting());
// Even if alwaysSend, we are waiting for a transition or remote to provide
- // rotated configuration, so we can't update configuration yet.
- if (!pendingRemoteRotation) {
+ // updated configuration, so we can't update configuration yet.
+ if (!pendingRemoteDisplayChange) {
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
layoutNeeded = true;
@@ -4297,17 +4288,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) {
+ public void setDisplayChangeWindowController(IDisplayChangeWindowController controller) {
mAtmService.enforceTaskPermission("setDisplayWindowRotationController");
try {
synchronized (mGlobalLock) {
- if (mDisplayRotationController != null) {
- mDisplayRotationController.asBinder().unlinkToDeath(
- mDisplayRotationControllerDeath, 0);
- mDisplayRotationController = null;
+ if (mDisplayChangeController != null) {
+ mDisplayChangeController.asBinder().unlinkToDeath(
+ mDisplayChangeControllerDeath, 0);
+ mDisplayChangeController = null;
}
- controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0);
- mDisplayRotationController = controller;
+ controller.asBinder().linkToDeath(mDisplayChangeControllerDeath, 0);
+ mDisplayChangeController = controller;
}
} catch (RemoteException e) {
throw new RuntimeException("Unable to set rotation controller");
@@ -5694,6 +5685,25 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ void setSandboxDisplayApis(int displayId, boolean sandboxDisplayApis) {
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.setSandboxDisplayApis(sandboxDisplayApis);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
/** The global settings only apply to default display. */
private boolean applyForcedPropertiesForDefaultDisplay() {
boolean changed = false;
@@ -5874,6 +5884,21 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void startTransitionTrace() {
+ mTransitionTracer.startTrace(null /* printwriter */);
+ }
+
+ @Override
+ public void stopTransitionTrace() {
+ mTransitionTracer.stopTrace(null /* printwriter */);
+ }
+
+ @Override
+ public boolean isTransitionTraceEnabled() {
+ return mTransitionTracer.isEnabled();
+ }
+
+ @Override
public boolean registerCrossWindowBlurEnabledListener(
ICrossWindowBlurEnabledListener listener) {
return mBlurController.registerCrossWindowBlurEnabledListener(listener);
@@ -6087,24 +6112,24 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId);
final int numOpeningApps;
final boolean waitingForConfig;
- final boolean waitingForRemoteRotation;
+ final boolean waitingForRemoteDisplayChange;
if (displayContent != null) {
numOpeningApps = displayContent.mOpeningApps.size();
waitingForConfig = displayContent.mWaitingForConfig;
- waitingForRemoteRotation =
- displayContent.getDisplayRotation().isWaitingForRemoteRotation();
+ waitingForRemoteDisplayChange = displayContent.mRemoteDisplayChangeController
+ .isWaitingForRemoteDisplayChange();
} else {
- waitingForConfig = waitingForRemoteRotation = false;
+ waitingForConfig = waitingForRemoteDisplayChange = false;
numOpeningApps = 0;
}
- if (waitingForConfig || waitingForRemoteRotation || mAppsFreezingScreen > 0
+ if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0
|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
|| mClientFreezingScreen || numOpeningApps > 0) {
ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "
- + "waitingForConfig=%b, waitingForRemoteRotation=%b, "
+ + "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, "
+ "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
+ "mClientFreezingScreen=%b, mOpeningApps.size()=%d",
- waitingForConfig, waitingForRemoteRotation,
+ waitingForConfig, waitingForRemoteDisplayChange,
mAppsFreezingScreen, mWindowsFreezingScreen,
mClientFreezingScreen, numOpeningApps);
return;
@@ -8215,7 +8240,7 @@ public class WindowManagerService extends IWindowManager.Stub
.setContainerLayer()
.setName("IME Handwriting Surface")
.setCallsite("getHandwritingSurfaceForDisplay")
- .setParent(dc.getSurfaceControl())
+ .setParent(dc.getOverlayLayer())
.build();
}
}
@@ -8753,7 +8778,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean getWindowInsets(WindowManager.LayoutParams attrs, int displayId,
InsetsState outInsetsState) {
- final boolean fromLocal = Binder.getCallingPid() == myPid();
+ final boolean fromLocal = Binder.getCallingPid() == MY_PID;
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 34c93482ecfe..02f056cd33af 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -19,6 +19,19 @@ package com.android.server.wm;
import static android.os.Build.IS_USER;
import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
+
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
@@ -36,6 +49,9 @@ import com.android.internal.os.ByteTransferPipe;
import com.android.internal.protolog.ProtoLogImpl;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
+import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
+import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
import java.io.IOException;
import java.io.PrintWriter;
@@ -58,10 +74,12 @@ public class WindowManagerShellCommand extends ShellCommand {
// Internal service impl -- must perform security checks before touching.
private final WindowManagerService mInternal;
+ private final LetterboxConfiguration mLetterboxConfiguration;
public WindowManagerShellCommand(WindowManagerService service) {
mInterface = service;
mInternal = service;
+ mLetterboxConfiguration = service.mLetterboxConfiguration;
}
@Override
@@ -113,6 +131,14 @@ public class WindowManagerShellCommand extends ShellCommand {
return runGetIgnoreOrientationRequest(pw);
case "dump-visible-window-views":
return runDumpVisibleWindowViews(pw);
+ case "set-letterbox-style":
+ return runSetLetterboxStyle(pw);
+ case "get-letterbox-style":
+ return runGetLetterboxStyle(pw);
+ case "reset-letterbox-style":
+ return runResetLetterboxStyle(pw);
+ case "set-sandbox-display-apis":
+ return runSandboxDisplayApis(pw);
case "set-multi-window-config":
return runSetMultiWindowConfig();
case "get-multi-window-config":
@@ -123,6 +149,8 @@ public class WindowManagerShellCommand extends ShellCommand {
return runReset(pw);
case "disable-blur":
return runSetBlurDisabled(pw);
+ case "shell":
+ return runWmShellCommand(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -331,6 +359,37 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ /**
+ * Override display size and metrics to reflect the DisplayArea of the calling activity.
+ */
+ private int runSandboxDisplayApis(PrintWriter pw) throws RemoteException {
+ int displayId = Display.DEFAULT_DISPLAY;
+ String arg = getNextArgRequired();
+ if ("-d".equals(arg)) {
+ displayId = Integer.parseInt(getNextArgRequired());
+ arg = getNextArgRequired();
+ }
+
+ final boolean sandboxDisplayApis;
+ switch (arg) {
+ case "true":
+ case "1":
+ sandboxDisplayApis = true;
+ break;
+ case "false":
+ case "0":
+ sandboxDisplayApis = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expecting true, 1, false, 0, but we "
+ + "get " + arg);
+ return -1;
+ }
+
+ mInternal.setSandboxDisplayApis(displayId, sandboxDisplayApis);
+ return 0;
+ }
+
private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
mInterface.dismissKeyguard(null /* callback */, null /* message */);
return 0;
@@ -553,6 +612,497 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runSetFixedOrientationLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
+ final float aspectRatio;
+ try {
+ String arg = getNextArgRequired();
+ aspectRatio = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad aspect ratio format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: aspect ratio should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(aspectRatio);
+ }
+ return 0;
+ }
+
+ private int runSetDefaultMinAspectRatioForUnresizableApps(PrintWriter pw)
+ throws RemoteException {
+ final float aspectRatio;
+ try {
+ String arg = getNextArgRequired();
+ aspectRatio = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad aspect ratio format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: aspect ratio should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setDefaultMinAspectRatioForUnresizableApps(aspectRatio);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
+ final int cornersRadius;
+ try {
+ String arg = getNextArgRequired();
+ cornersRadius = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad corners radius format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: corners radius should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxActivityCornersRadius(cornersRadius);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxBackgroundType(PrintWriter pw) throws RemoteException {
+ @LetterboxBackgroundType final int backgroundType;
+ try {
+ String arg = getNextArgRequired();
+ switch (arg) {
+ case "solid_color":
+ backgroundType = LETTERBOX_BACKGROUND_SOLID_COLOR;
+ break;
+ case "app_color_background":
+ backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+ break;
+ case "app_color_background_floating":
+ backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+ break;
+ case "wallpaper":
+ backgroundType = LETTERBOX_BACKGROUND_WALLPAPER;
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: 'solid_color', 'app_color_background' or "
+ + "'wallpaper' should be provided as an argument");
+ return -1;
+ }
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'solid_color', 'app_color_background' or "
+ + "'wallpaper' should be provided as an argument" + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundType(backgroundType);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxBackgroundColorResource(PrintWriter pw) throws RemoteException {
+ final int colorId;
+ try {
+ String arg = getNextArgRequired();
+ colorId = mInternal.mContext.getResources()
+ .getIdentifier(arg, "color", "com.android.internal");
+ } catch (NotFoundException e) {
+ getErrPrintWriter().println(
+ "Error: color in '@android:color/resource_name' format should be provided as "
+ + "an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundColorResourceId(colorId);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxBackgroundColor(PrintWriter pw) throws RemoteException {
+ final Color color;
+ try {
+ String arg = getNextArgRequired();
+ color = Color.valueOf(Color.parseColor(arg));
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: color in #RRGGBB format should be provided as "
+ + "an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundColor(color);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxBackgroundWallpaperBlurRadius(PrintWriter pw)
+ throws RemoteException {
+ final int radius;
+ try {
+ String arg = getNextArgRequired();
+ radius = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: blur radius format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: blur radius should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundWallpaperBlurRadius(radius);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxBackgroundWallpaperDarkScrimAlpha(PrintWriter pw)
+ throws RemoteException {
+ final float alpha;
+ try {
+ String arg = getNextArgRequired();
+ alpha = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad alpha format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: alpha should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxBackgroundWallpaperDarkScrimAlpha(alpha);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
+ final float multiplier;
+ try {
+ String arg = getNextArgRequired();
+ multiplier = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad multiplier format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: multiplier should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(multiplier);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxVerticalPositionMultiplier(PrintWriter pw) throws RemoteException {
+ final float multiplier;
+ try {
+ String arg = getNextArgRequired();
+ multiplier = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad multiplier format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: multiplier should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(multiplier);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxIsHorizontalReachabilityEnabled(PrintWriter pw)
+ throws RemoteException {
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(enabled);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxIsVerticalReachabilityEnabled(PrintWriter pw)
+ throws RemoteException {
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsVerticalReachabilityEnabled(enabled);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxDefaultPositionForHorizontalReachability(PrintWriter pw)
+ throws RemoteException {
+ @LetterboxHorizontalReachabilityPosition final int position;
+ try {
+ String arg = getNextArgRequired();
+ switch (arg) {
+ case "left":
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
+ break;
+ case "center":
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
+ break;
+ case "right":
+ position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: 'left', 'center' or 'right' are expected as an argument");
+ return -1;
+ }
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'left', 'center' or 'right' are expected as an argument" + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setDefaultPositionForHorizontalReachability(position);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxDefaultPositionForVerticalReachability(PrintWriter pw)
+ throws RemoteException {
+ @LetterboxVerticalReachabilityPosition final int position;
+ try {
+ String arg = getNextArgRequired();
+ switch (arg) {
+ case "top":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
+ break;
+ case "center":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
+ break;
+ case "bottom":
+ position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: 'top', 'center' or 'bottom' are expected as an argument");
+ return -1;
+ }
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'top', 'center' or 'bottom' are expected as an argument" + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setDefaultPositionForVerticalReachability(position);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxIsEducationEnabled(PrintWriter pw) throws RemoteException {
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsEducationEnabled(enabled);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled(PrintWriter pw)
+ throws RemoteException {
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsSplitScreenAspectRatioForUnresizableAppsEnabled(enabled);
+ }
+ return 0;
+ }
+
+ private int runSetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ if (peekNextArg() == null) {
+ getErrPrintWriter().println("Error: No arguments provided.");
+ }
+ while (peekNextArg() != null) {
+ String arg = getNextArg();
+ switch (arg) {
+ case "--aspectRatio":
+ runSetFixedOrientationLetterboxAspectRatio(pw);
+ break;
+ case "--minAspectRatioForUnresizable":
+ runSetDefaultMinAspectRatioForUnresizableApps(pw);
+ break;
+ case "--cornerRadius":
+ runSetLetterboxActivityCornersRadius(pw);
+ break;
+ case "--backgroundType":
+ runSetLetterboxBackgroundType(pw);
+ break;
+ case "--backgroundColor":
+ runSetLetterboxBackgroundColor(pw);
+ break;
+ case "--backgroundColorResource":
+ runSetLetterboxBackgroundColorResource(pw);
+ break;
+ case "--wallpaperBlurRadius":
+ runSetLetterboxBackgroundWallpaperBlurRadius(pw);
+ break;
+ case "--wallpaperDarkScrimAlpha":
+ runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
+ break;
+ case "--horizontalPositionMultiplier":
+ runSetLetterboxHorizontalPositionMultiplier(pw);
+ break;
+ case "--verticalPositionMultiplier":
+ runSetLetterboxVerticalPositionMultiplier(pw);
+ break;
+ case "--isHorizontalReachabilityEnabled":
+ runSetLetterboxIsHorizontalReachabilityEnabled(pw);
+ break;
+ case "--isVerticalReachabilityEnabled":
+ runSetLetterboxIsVerticalReachabilityEnabled(pw);
+ break;
+ case "--defaultPositionForHorizontalReachability":
+ runSetLetterboxDefaultPositionForHorizontalReachability(pw);
+ break;
+ case "--defaultPositionForVerticalReachability":
+ runSetLetterboxDefaultPositionForVerticalReachability(pw);
+ break;
+ case "--isEducationEnabled":
+ runSetLetterboxIsEducationEnabled(pw);
+ break;
+ case "--isSplitScreenAspectRatioForUnresizableAppsEnabled":
+ runSetLetterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled(pw);
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: Unrecognized letterbox style option: " + arg);
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ private int runResetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ if (peekNextArg() == null) {
+ resetLetterboxStyle();
+ }
+ synchronized (mInternal.mGlobalLock) {
+ while (peekNextArg() != null) {
+ String arg = getNextArg();
+ switch (arg) {
+ case "aspectRatio":
+ mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ break;
+ case "minAspectRatioForUnresizable":
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
+ break;
+ case "cornerRadius":
+ mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+ break;
+ case "backgroundType":
+ mLetterboxConfiguration.resetLetterboxBackgroundType();
+ break;
+ case "backgroundColor":
+ mLetterboxConfiguration.resetLetterboxBackgroundColor();
+ break;
+ case "wallpaperBlurRadius":
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ break;
+ case "wallpaperDarkScrimAlpha":
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+ break;
+ case "horizontalPositionMultiplier":
+ mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+ break;
+ case "verticalPositionMultiplier":
+ mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
+ break;
+ case "isHorizontalReachabilityEnabled":
+ mLetterboxConfiguration.getIsHorizontalReachabilityEnabled();
+ break;
+ case "isVerticalReachabilityEnabled":
+ mLetterboxConfiguration.getIsVerticalReachabilityEnabled();
+ break;
+ case "defaultPositionForHorizontalReachability":
+ mLetterboxConfiguration.getDefaultPositionForHorizontalReachability();
+ break;
+ case "defaultPositionForVerticalReachability":
+ mLetterboxConfiguration.getDefaultPositionForVerticalReachability();
+ break;
+ case "isEducationEnabled":
+ mLetterboxConfiguration.getIsEducationEnabled();
+ break;
+ case "isSplitScreenAspectRatioForUnresizableAppsEnabled":
+ mLetterboxConfiguration
+ .getIsSplitScreenAspectRatioForUnresizableAppsEnabled();
+ break;
+ default:
+ getErrPrintWriter().println(
+ "Error: Unrecognized letterbox style option: " + arg);
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+
private int runSetMultiWindowConfig() {
if (peekNextArg() == null) {
getErrPrintWriter().println("Error: No arguments provided.");
@@ -627,6 +1177,107 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private void resetLetterboxStyle() {
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
+ mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundType();
+ mLetterboxConfiguration.resetLetterboxBackgroundColor();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+ mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+ mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
+ mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
+ mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
+ mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
+ mLetterboxConfiguration.resetIsEducationEnabled();
+ mLetterboxConfiguration.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
+ }
+ }
+
+ private int runGetLetterboxStyle(PrintWriter pw) throws RemoteException {
+ synchronized (mInternal.mGlobalLock) {
+ pw.println("Corner radius: "
+ + mLetterboxConfiguration.getLetterboxActivityCornersRadius());
+ pw.println("Horizontal position multiplier: "
+ + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
+ pw.println("Vertical position multiplier: "
+ + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier());
+ pw.println("Aspect ratio: "
+ + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+ pw.println("Default min aspect ratio for unresizable apps: "
+ + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
+ pw.println("Is horizontal reachability enabled: "
+ + mLetterboxConfiguration.getIsHorizontalReachabilityEnabled());
+ pw.println("Is vertical reachability enabled: "
+ + mLetterboxConfiguration.getIsVerticalReachabilityEnabled());
+ pw.println("Default position for horizontal reachability: "
+ + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
+ mLetterboxConfiguration.getDefaultPositionForHorizontalReachability()));
+ pw.println("Default position for vertical reachability: "
+ + LetterboxConfiguration.letterboxVerticalReachabilityPositionToString(
+ mLetterboxConfiguration.getDefaultPositionForVerticalReachability()));
+ pw.println("Is education enabled: "
+ + mLetterboxConfiguration.getIsEducationEnabled());
+ pw.println("Is using split screen aspect ratio as aspect ratio for unresizable apps: "
+ + mLetterboxConfiguration
+ .getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
+
+ pw.println("Background type: "
+ + LetterboxConfiguration.letterboxBackgroundTypeToString(
+ mLetterboxConfiguration.getLetterboxBackgroundType()));
+ pw.println(" Background color: " + Integer.toHexString(
+ mLetterboxConfiguration.getLetterboxBackgroundColor().toArgb()));
+ pw.println(" Wallpaper blur radius: "
+ + mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius());
+ pw.println(" Wallpaper dark scrim alpha: "
+ + mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha());
+ }
+ return 0;
+ }
+
+ private int runWmShellCommand(PrintWriter pw) {
+ String arg = getNextArg();
+
+ switch (arg) {
+ case "tracing":
+ return runWmShellTracing(pw);
+ case "help":
+ default:
+ return runHelp(pw);
+ }
+ }
+
+ private int runHelp(PrintWriter pw) {
+ pw.println("Window Manager Shell commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" tracing <start/stop>");
+ pw.println(" Start/stop shell transition tracing.");
+
+ return 0;
+ }
+
+ private int runWmShellTracing(PrintWriter pw) {
+ String arg = getNextArg();
+
+ switch (arg) {
+ case "start":
+ mInternal.mTransitionTracer.startTrace(pw);
+ break;
+ case "stop":
+ mInternal.mTransitionTracer.stopTrace(pw);
+ break;
+ default:
+ getErrPrintWriter()
+ .println("Error: expected 'start' or 'stop', but got '" + arg + "'");
+ return -1;
+ }
+
+ return 0;
+ }
+
private int runReset(PrintWriter pw) throws RemoteException {
int displayId = getDisplayId(getNextArg());
@@ -651,6 +1302,12 @@ public class WindowManagerShellCommand extends ShellCommand {
// set-ignore-orientation-request
mInterface.setIgnoreOrientationRequest(displayId, false /* ignoreOrientationRequest */);
+ // set-letterbox-style
+ resetLetterboxStyle();
+
+ // set-sandbox-display-apis
+ mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true);
+
// set-multi-window-config
runResetMultiWindowConfig();
@@ -685,7 +1342,12 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println(" set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]");
pw.println(" get-ignore-orientation-request [-d DISPLAY_ID] ");
pw.println(" If app requested orientation should be ignored.");
+ pw.println(" set-sandbox-display-apis [true|1|false|0]");
+ pw.println(" Sets override of Display APIs getRealSize / getRealMetrics to reflect ");
+ pw.println(" DisplayArea of the activity, or the window bounds if in letterbox or");
+ pw.println(" Size Compat Mode.");
+ printLetterboxHelp(pw);
printMultiWindowConfigHelp(pw);
pw.println(" reset [-d DISPLAY_ID]");
@@ -698,6 +1360,83 @@ public class WindowManagerShellCommand extends ShellCommand {
}
}
+ private void printLetterboxHelp(PrintWriter pw) {
+ pw.println(" set-letterbox-style");
+ pw.println(" Sets letterbox style using the following options:");
+ pw.println(" --aspectRatio aspectRatio");
+ pw.println(" Aspect ratio of letterbox for fixed orientation. If aspectRatio <= "
+ + LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
+ pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will");
+ pw.println(" be ignored and framework implementation will determine aspect ratio.");
+ pw.println(" --minAspectRatioForUnresizable aspectRatio");
+ pw.println(" Default min aspect ratio for unresizable apps which is used when an");
+ pw.println(" app doesn't specify android:minAspectRatio. An exception will be");
+ pw.println(" thrown if aspectRatio < "
+ + LetterboxConfiguration.MIN_UNRESIZABLE_ASPECT_RATIO);
+ pw.println(" --cornerRadius radius");
+ pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
+ pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be");
+ pw.println(" ignored and corners of the activity won't be rounded.");
+ pw.println(" --backgroundType [reset|solid_color|app_color_background");
+ pw.println(" |app_color_background_floating|wallpaper]");
+ pw.println(" Type of background used in the letterbox mode.");
+ pw.println(" --backgroundColor color");
+ pw.println(" Color of letterbox which is be used when letterbox background type");
+ pw.println(" is 'solid-color'. Use (set)get-letterbox-style to check and control");
+ pw.println(" letterbox background type. See Color#parseColor for allowed color");
+ pw.println(" formats (#RRGGBB and some colors by name, e.g. magenta or olive).");
+ pw.println(" --backgroundColorResource resource_name");
+ pw.println(" Color resource name of letterbox background which is used when");
+ pw.println(" background type is 'solid-color'. Use (set)get-letterbox-style to");
+ pw.println(" check and control background type. Parameter is a color resource");
+ pw.println(" name, for example, @android:color/system_accent2_50.");
+ pw.println(" --wallpaperBlurRadius radius");
+ pw.println(" Blur radius for 'wallpaper' letterbox background. If radius <= 0");
+ pw.println(" both it and R.dimen.config_letterboxBackgroundWallpaperBlurRadius");
+ pw.println(" are ignored and 0 is used.");
+ pw.println(" --wallpaperDarkScrimAlpha alpha");
+ pw.println(" Alpha of a black translucent scrim shown over 'wallpaper'");
+ pw.println(" letterbox background. If alpha < 0 or >= 1 both it and");
+ pw.println(" R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored");
+ pw.println(" and 0.0 (transparent) is used instead.");
+ pw.println(" --horizontalPositionMultiplier multiplier");
+ pw.println(" Horizontal position of app window center. If multiplier < 0 or > 1,");
+ pw.println(" both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
+ pw.println(" are ignored and central position (0.5) is used.");
+ pw.println(" --verticalPositionMultiplier multiplier");
+ pw.println(" Vertical position of app window center. If multiplier < 0 or > 1,");
+ pw.println(" both it and R.dimen.config_letterboxVerticalPositionMultiplier");
+ pw.println(" are ignored and central position (0.5) is used.");
+ pw.println(" --isHorizontalReachabilityEnabled [true|1|false|0]");
+ pw.println(" Whether horizontal reachability repositioning is allowed for ");
+ pw.println(" letterboxed fullscreen apps in landscape device orientation.");
+ pw.println(" --isVerticalReachabilityEnabled [true|1|false|0]");
+ pw.println(" Whether vertical reachability repositioning is allowed for ");
+ pw.println(" letterboxed fullscreen apps in portrait device orientation.");
+ pw.println(" --defaultPositionForHorizontalReachability [left|center|right]");
+ pw.println(" Default position of app window when horizontal reachability is.");
+ pw.println(" enabled.");
+ pw.println(" --defaultPositionForVerticalReachability [top|center|bottom]");
+ pw.println(" Default position of app window when vertical reachability is.");
+ pw.println(" enabled.");
+ pw.println(" --isEducationEnabled [true|1|false|0]");
+ pw.println(" Whether education is allowed for letterboxed fullscreen apps.");
+ pw.println(" --isSplitScreenAspectRatioForUnresizableAppsEnabled [true|1|false|0]");
+ pw.println(" Whether using split screen aspect ratio as a default aspect ratio for");
+ pw.println(" unresizable apps.");
+ pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
+ pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
+ pw.println(" |horizontalPositionMultiplier|verticalPositionMultiplier");
+ pw.println(" |isHorizontalReachabilityEnabled|isVerticalReachabilityEnabled");
+ pw.println(" isEducationEnabled||defaultPositionMultiplierForHorizontalReachability");
+ pw.println(" ||defaultPositionMultiplierForVerticalReachability]");
+ pw.println(" Resets overrides to default values for specified properties separated");
+ pw.println(" by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
+ pw.println(" If no arguments provided, all values will be reset.");
+ pw.println(" get-letterbox-style");
+ pw.println(" Prints letterbox style configuration.");
+ }
+
private void printMultiWindowConfigHelp(PrintWriter pw) {
pw.println(" set-multi-window-config");
pw.println(" Sets options to determine if activity should be shown in multi window:");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ff3b4a5bb44f..d4d8dd8bceb1 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -18,6 +18,8 @@ package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
@@ -42,6 +44,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -56,6 +59,7 @@ import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -115,7 +119,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
static final int CONTROLLABLE_CONFIGS = ActivityInfo.CONFIG_WINDOW_CONFIGURATION
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_LAYOUT_DIRECTION;
- static final int CONTROLLABLE_WINDOW_CONFIGS = WindowConfiguration.WINDOW_CONFIG_BOUNDS
+ static final int CONTROLLABLE_WINDOW_CONFIGS = WINDOW_CONFIG_BOUNDS
| WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
private final ActivityTaskManagerService mService;
@@ -145,7 +149,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
void setWindowManager(WindowManagerService wms) {
- mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
+ mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController,
+ wms.mTransitionTracer);
mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
}
@@ -395,6 +400,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
}
+ final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
+ final int hopSize = hops.size();
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
t.getChanges().entrySet().iterator();
@@ -413,17 +420,43 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (transition != null) transition.collect(wc);
- if (finishTransition != null) {
- // Deal with edge-cases in recents where it pretends to finish itself.
- if ((entry.getValue().getChangeMask()
- & WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
+ if ((entry.getValue().getChangeMask()
+ & WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
+ // Disable entering pip (eg. when recents pretends to finish itself)
+ if (finishTransition != null) {
finishTransition.setCanPipOnFinish(false /* canPipOnFinish */);
+ } else if (transition != null) {
+ transition.setCanPipOnFinish(false /* canPipOnFinish */);
+ }
+ }
+ // A bit hacky, but we need to detect "remove PiP" so that we can "wrap" the
+ // setWindowingMode call in force-hidden.
+ boolean forceHiddenForPip = false;
+ if (wc.asTask() != null && wc.inPinnedWindowingMode()
+ && entry.getValue().getWindowingMode() == WINDOWING_MODE_UNDEFINED) {
+ // We are in pip and going to undefined. Now search hierarchy ops to determine
+ // whether we are removing pip or expanding pip.
+ for (int i = 0; i < hopSize; ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+ if (hop.getType() != HIERARCHY_OP_TYPE_REORDER) continue;
+ final WindowContainer hopWc = WindowContainer.fromBinder(
+ hop.getContainer());
+ if (!wc.equals(hopWc)) continue;
+ forceHiddenForPip = !hop.getToTop();
}
}
+ if (forceHiddenForPip) {
+ wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ }
- int containerEffect = applyWindowContainerChange(wc, entry.getValue());
+ int containerEffect = applyWindowContainerChange(wc, entry.getValue(),
+ t.getErrorCallbackToken());
effects |= containerEffect;
+ if (forceHiddenForPip) {
+ wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
+ }
+
// Lifecycle changes will trigger ensureConfig for everything.
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
@@ -431,8 +464,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
// Hierarchy changes
- final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
- final int hopSize = hops.size();
if (hopSize > 0) {
final boolean isInLockTaskMode = mService.isInLockTaskMode();
for (int i = 0; i < hopSize; ++i) {
@@ -503,7 +534,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
- private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) {
+ private int applyChanges(WindowContainer<?> container,
+ WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
// The "client"-facing API should prevent bad changes; however, just in case, sanitize
// masks here.
final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
@@ -511,6 +543,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
int effects = 0;
final int windowingMode = change.getWindowingMode();
if (configMask != 0) {
+
+ adjustBoundsForMinDimensionsIfNeeded(container, change, errorCallbackToken);
+
if (windowingMode > -1 && windowingMode != container.getWindowingMode()) {
// Special handling for when we are setting a windowingMode in the same transaction.
// Setting the windowingMode is going to call onConfigurationChanged so we don't
@@ -544,6 +579,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ " windowing mode during locked task mode.");
}
+ if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED) {
+ // Do not directly put the container into PINNED mode as it may not support it or
+ // the app may not want to enter it. Instead, send a signal to request PIP
+ // mode to the app if they wish to support it below in #applyTaskChanges.
+ return effects;
+ }
+
final int prevMode = container.getWindowingMode();
container.setWindowingMode(windowingMode);
if (prevMode != container.getWindowingMode()) {
@@ -556,6 +598,26 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
+ private void adjustBoundsForMinDimensionsIfNeeded(WindowContainer<?> container,
+ WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
+ final TaskFragment taskFragment = container.asTaskFragment();
+ if (taskFragment == null || !taskFragment.isEmbedded()) {
+ return;
+ }
+ if ((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) == 0) {
+ return;
+ }
+ final WindowConfiguration winConfig = change.getConfiguration().windowConfiguration;
+ final Rect bounds = winConfig.getBounds();
+ final Point minDimensions = taskFragment.calculateMinDimension();
+ if (bounds.width() < minDimensions.x || bounds.height() < minDimensions.y) {
+ sendMinimumDimensionViolation(taskFragment, minDimensions, errorCallbackToken,
+ "setBounds:" + bounds);
+ // Sets the bounds to match parent bounds.
+ winConfig.setBounds(new Rect());
+ }
+ }
+
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
int effects = 0;
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
@@ -580,6 +642,28 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
tr.mDisplayContent.mPinnedTaskController.setEnterPipBounds(enterPipBounds);
}
+ if (c.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_PINNED
+ && !tr.inPinnedWindowingMode()) {
+ final ActivityRecord activity = tr.getTopNonFinishingActivity();
+ if (activity != null) {
+ final boolean lastSupportsEnterPipOnTaskSwitch =
+ activity.supportsEnterPipOnTaskSwitch;
+ // Temporarily force enable enter PIP on task switch so that PIP is requested
+ // regardless of whether the activity is resumed or paused.
+ activity.supportsEnterPipOnTaskSwitch = true;
+ boolean canEnterPip = activity.checkEnterPictureInPictureState(
+ "applyTaskChanges", true /* beforeStopping */);
+ if (canEnterPip) {
+ canEnterPip = mService.mActivityClientController
+ .requestPictureInPictureMode(activity);
+ }
+ if (!canEnterPip) {
+ // Restore the flag to its previous state when the activity cannot enter PIP.
+ activity.supportsEnterPipOnTaskSwitch = lastSupportsEnterPipOnTaskSwitch;
+ }
+ }
+ }
+
return effects;
}
@@ -696,7 +780,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Bundle activityOptions = hop.getLaunchOptions();
final int result = mService.getActivityStartController()
.startActivityInTaskFragment(tf, activityIntent, activityOptions,
- hop.getCallingActivity(), caller.mUid, caller.mPid);
+ hop.getCallingActivity(), caller.mUid, caller.mPid,
+ errorCallbackToken);
if (!isStartResultSuccessful(result)) {
sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
convertStartFailureToThrowable(result, activityIntent));
@@ -740,6 +825,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
+ if (parent.smallerThanMinDimension(activity)) {
+ sendMinimumDimensionViolation(parent, activity.getMinDimensions(),
+ errorCallbackToken, "reparentActivityToTask");
+ break;
+ }
+
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
@@ -764,7 +855,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
- tf1.setAdjacentTaskFragment(tf2, false /* moveAdjacentTogether */);
+ tf1.setAdjacentTaskFragment(tf2);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
final Bundle bundle = hop.getLaunchOptions();
@@ -806,22 +897,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
tf.getDisplayContent().setFocusedApp(targetFocus);
break;
}
- default: {
- // The other operations may change task order so they are skipped while in lock
- // task mode. The above operations are still allowed because they don't move
- // tasks. And it may be necessary such as clearing launch root after entering
- // lock task mode.
- if (isInLockTaskMode) {
- Slog.w(TAG, "Skip applying hierarchy operation " + hop
- + " while in lock task mode");
- return effects;
- }
- }
- }
-
- switch (type) {
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
- effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId,
+ isInLockTaskMode);
+ break;
+ }
+ case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
+ mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "launchTask HierarchyOp");
+ final Bundle launchOpts = hop.getLaunchOptions();
+ final int taskId = launchOpts.getInt(
+ WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
+ launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
+ final SafeActivityOptions safeOptions =
+ SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+ waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
+ caller.mPid, caller.mUid, taskId, safeOptions));
break;
}
case HIERARCHY_OP_TYPE_REORDER:
@@ -831,6 +922,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
break;
}
+ // There is no use case to ask the reparent operation in lock-task mode now, so keep
+ // skipping this operation as usual.
+ if (isInLockTaskMode && type == HIERARCHY_OP_TYPE_REPARENT) {
+ Slog.w(TAG, "Skip applying hierarchy operation " + hop
+ + " while in lock task mode");
+ break;
+ }
+ if (isLockTaskModeViolation(wc.getParent(), wc.asTask(), isInLockTaskMode)) {
+ break;
+ }
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
@@ -856,19 +957,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
break;
}
- case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
- mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
- "launchTask HierarchyOp");
- final Bundle launchOpts = hop.getLaunchOptions();
- final int taskId = launchOpts.getInt(
- WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
- launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
- final SafeActivityOptions safeOptions =
- SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
- waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
- caller.mPid, caller.mUid, taskId, safeOptions));
- break;
+ default: {
+ // The other operations may change task order so they are skipped while in lock
+ // task mode. The above operations are still allowed because they don't move
+ // tasks. And it may be necessary such as clearing launch root after entering
+ // lock task mode.
+ if (isInLockTaskMode) {
+ Slog.w(TAG, "Skip applying hierarchy operation " + hop
+ + " while in lock task mode");
+ return effects;
+ }
}
+ }
+
+ switch (type) {
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
String resolvedType = hop.getActivityIntent() != null
? hop.getActivityIntent().resolveTypeIfNeeded(
@@ -953,6 +1055,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
+ /** A helper method to send minimum dimension violation error to the client. */
+ void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
+ IBinder errorCallbackToken, String reason) {
+ if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
+ return;
+ }
+ final Throwable exception = new SecurityException("The task fragment's bounds:"
+ + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ + minDimensions + " " + reason);
+ sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ }
+
/**
* Post and wait for the result of the activity start to prevent potential deadlock against
* {@link WindowManagerGlobalLock}.
@@ -1047,8 +1162,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return TRANSACT_EFFECTS_LIFECYCLE;
}
+ private boolean isLockTaskModeViolation(WindowContainer parent, Task task,
+ boolean isInLockTaskMode) {
+ if (!isInLockTaskMode || parent == null || task == null) {
+ return false;
+ }
+ final LockTaskController lockTaskController = mService.getLockTaskController();
+ boolean taskViolation = lockTaskController.isLockTaskModeViolation(task);
+ if (!taskViolation && parent.asTask() != null) {
+ taskViolation = lockTaskController.isLockTaskModeViolation(parent.asTask());
+ }
+ if (taskViolation) {
+ Slog.w(TAG, "Can't support the operation since in lock task mode violation. "
+ + " Task: " + task + " Parent : " + parent);
+ }
+ return taskViolation;
+ }
+
private int reparentChildrenTasksHierarchyOp(WindowContainerTransaction.HierarchyOp hop,
- @Nullable Transition transition, int syncId) {
+ @Nullable Transition transition, int syncId, boolean isInLockTaskMode) {
WindowContainer<?> currentParent = hop.getContainer() != null
? WindowContainer.fromBinder(hop.getContainer()) : null;
WindowContainer newParent = hop.getNewParent() != null
@@ -1086,6 +1218,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
? newParent.asTask().getDisplayArea()
: newParent.asTaskDisplayArea();
final WindowContainer finalCurrentParent = currentParent;
+ final WindowContainer finalNewParent = newParent;
Slog.i(TAG, "reparentChildrenTasksHierarchyOp"
+ " currentParent=" + currentParent + " newParent=" + newParent + " hop=" + hop);
@@ -1109,6 +1242,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|| !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) {
return false;
}
+ if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) {
+ return false;
+ }
if (hop.getToTop()) {
tasksToReparent.add(0, task);
@@ -1153,7 +1289,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
Slog.e(TAG, "Attempt to set adjacent TaskFragment in PIP Task");
return 0;
}
- root1.setAdjacentTaskFragment(root2, hop.getMoveAdjacentTogether());
+ root1.setAdjacentTaskFragment(root2);
return TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -1164,14 +1300,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
private int applyWindowContainerChange(WindowContainer wc,
- WindowContainerTransaction.Change c) {
+ WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
sanitizeWindowContainer(wc);
if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbeddedTaskFragmentInPip()) {
// No override from organizer for embedded TaskFragment in a PIP Task.
return 0;
}
- int effects = applyChanges(wc, c);
+ int effects = applyChanges(wc, c, errorCallbackToken);
if (wc instanceof DisplayArea) {
effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
@@ -1515,8 +1651,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
}
- void reparentTaskFragment(@NonNull TaskFragment oldParent, @Nullable WindowContainer newParent,
- @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
+ void reparentTaskFragment(@NonNull TaskFragment oldParent,
+ @Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
+ @Nullable IBinder errorCallbackToken) {
final TaskFragment newParentTF;
if (newParent == null) {
// Use the old parent's parent if the caller doesn't specify the new parent.
@@ -1554,6 +1691,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
+ final Point minDimensions = oldParent.calculateMinDimension();
+ final Rect newParentBounds = newParentTF.getBounds();
+ if (newParentBounds.width() < minDimensions.x
+ || newParentBounds.height() < minDimensions.y) {
+ sendMinimumDimensionViolation(newParentTF, minDimensions, errorCallbackToken,
+ "reparentTaskFragment");
+ return;
+ }
while (oldParent.hasChild()) {
oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
}
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index de87ab9dcce0..3e165e442d79 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -296,9 +296,9 @@ public abstract class WindowOrientationListener {
/**
* Whether the device is in the lock screen.
- * @return returns true if the screen is locked. Otherwise, returns false.
+ * @return returns true if the key guard is showing on the lock screen.
*/
- public abstract boolean isKeyguardLocked();
+ public abstract boolean isKeyguardShowingAndNotOccluded();
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
@@ -1151,7 +1151,7 @@ public abstract class WindowOrientationListener {
FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT);
if (isRotationResolverEnabled()) {
- if (isKeyguardLocked()) {
+ if (isKeyguardShowingAndNotOccluded()) {
if (mLastRotationResolution != ROTATION_UNSET
&& SystemClock.uptimeMillis() - mLastRotationResolutionTimeStamp
< mRotationMemorizationTimeoutMillis) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 40417a4857d3..3ff912cca091 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
@@ -24,7 +25,6 @@ import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
import static com.android.server.wm.ActivityRecord.State.DESTROYING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
@@ -39,6 +39,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import android.Manifest;
import android.annotation.NonNull;
@@ -195,6 +196,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/** Whether the process configuration is waiting to be dispatched to the process. */
private boolean mHasPendingConfigurationChange;
+ /** If the process state is in (<=) the cached state, then defer delivery of the config. */
+ private static final int CACHED_CONFIG_PROC_STATE = PROCESS_STATE_CACHED_ACTIVITY;
+ /** Whether {@link #mLastReportedConfiguration} is deferred by the cached state. */
+ private volatile boolean mHasCachedConfiguration;
+
/**
* Registered {@link DisplayArea} as a listener to override config changes. {@code null} if not
* registered.
@@ -316,8 +322,27 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mCurProcState;
}
+ /**
+ * Sets the computed process state from the oom adjustment calculation. This is frequently
+ * called in activity manager's lock, so don't use window manager lock here.
+ */
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public void setReportedProcState(int repProcState) {
+ final int prevProcState = mRepProcState;
mRepProcState = repProcState;
+
+ // Deliver the cached config if the app changes from cached state to non-cached state.
+ final IApplicationThread thread = mThread;
+ if (prevProcState >= CACHED_CONFIG_PROC_STATE && repProcState < CACHED_CONFIG_PROC_STATE
+ && thread != null && mHasCachedConfiguration) {
+ final Configuration config;
+ synchronized (mLastReportedConfiguration) {
+ config = new Configuration(mLastReportedConfiguration);
+ }
+ // Schedule immediately to make sure the app component (e.g. receiver, service) can get
+ // the latest configuration in their lifecycle callbacks (e.g. onReceive, onCreate).
+ scheduleConfigurationChange(thread, config);
+ }
}
int getReportedProcState() {
@@ -1126,6 +1151,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mAtm.mH.sendMessage(m);
}
+ /** Refreshes oom adjustment and process state of this process. */
+ void scheduleUpdateOomAdj() {
+ mAtm.mH.sendMessage(PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
+ mListener, false /* updateServiceConnectionActivities */,
+ false /* activityChange */, true /* updateOomAdj */));
+ }
+
/** Makes the process have top state before oom-adj is computed from a posted message. */
void addToPendingTop() {
mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread);
@@ -1328,12 +1360,22 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@Override
public void onConfigurationChanged(Configuration newGlobalConfig) {
super.onConfigurationChanged(newGlobalConfig);
- updateConfiguration();
- }
+ final Configuration config = getConfiguration();
+ if (mLastReportedConfiguration.equals(config)) {
+ // Nothing changed.
+ if (Build.IS_DEBUGGABLE && mHasImeService) {
+ // TODO (b/135719017): Temporary log for debugging IME service.
+ Slog.w(TAG_CONFIGURATION, "Current config: " + config
+ + " unchanged for IME proc " + mName);
+ }
+ return;
+ }
- @Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ if (mPauseConfigurationDispatchCount > 0) {
+ mHasPendingConfigurationChange = true;
+ return;
+ }
+ dispatchConfiguration(config);
}
@Override
@@ -1359,25 +1401,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
resolvedConfig.seq = newParentConfig.seq;
}
- private void updateConfiguration() {
- final Configuration config = getConfiguration();
- if (mLastReportedConfiguration.diff(config) == 0) {
- // Nothing changed.
- if (Build.IS_DEBUGGABLE && mHasImeService) {
- // TODO (b/135719017): Temporary log for debugging IME service.
- Slog.w(TAG_CONFIGURATION, "Current config: " + config
- + " unchanged for IME proc " + mName);
- }
- return;
- }
-
- if (mPauseConfigurationDispatchCount > 0) {
- mHasPendingConfigurationChange = true;
- return;
- }
- dispatchConfiguration(config);
- }
-
void dispatchConfiguration(Configuration config) {
mHasPendingConfigurationChange = false;
if (mThread == null) {
@@ -1388,29 +1411,47 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
return;
}
+
+ config.seq = mAtm.increaseConfigurationSeqLocked();
+ setLastReportedConfiguration(config);
+
+ // A cached process doesn't have running application components, so it is unnecessary to
+ // notify the configuration change. The last-reported-configuration is still set because
+ // setReportedProcState() should not write any fields that require WM lock.
+ if (mRepProcState >= CACHED_CONFIG_PROC_STATE) {
+ mHasCachedConfiguration = true;
+ // Because there are 2 volatile accesses in setReportedProcState(): mRepProcState and
+ // mHasCachedConfiguration, check again in case mRepProcState is changed but hasn't
+ // read the change of mHasCachedConfiguration.
+ if (mRepProcState >= CACHED_CONFIG_PROC_STATE) {
+ return;
+ }
+ }
+
+ scheduleConfigurationChange(mThread, config);
+ }
+
+ private void scheduleConfigurationChange(IApplicationThread thread, Configuration config) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
}
-
+ mHasCachedConfiguration = false;
try {
- config.seq = mAtm.increaseConfigurationSeqLocked();
- mAtm.getLifecycleManager().scheduleTransaction(mThread,
+ mAtm.getLifecycleManager().scheduleTransaction(thread,
ConfigurationChangeItem.obtain(config));
- setLastReportedConfiguration(config);
} catch (Exception e) {
- Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change: " + mOwner, e);
}
}
void setLastReportedConfiguration(Configuration config) {
- mLastReportedConfiguration.setTo(config);
- }
-
- Configuration getLastReportedConfiguration() {
- return mLastReportedConfiguration;
+ // Synchronize for the access from setReportedProcState().
+ synchronized (mLastReportedConfiguration) {
+ mLastReportedConfiguration.setTo(config);
+ }
}
void pauseConfigurationDispatch() {
@@ -1461,6 +1502,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// config seq. This increment ensures that the client won't ignore the configuration.
config.seq = mAtm.increaseConfigurationSeqLocked();
}
+ // LaunchActivityItem includes the latest process configuration.
+ mHasCachedConfiguration = false;
return config;
}
@@ -1688,7 +1731,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
pw.println(prefix + " Configuration=" + getConfiguration());
pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
- pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
+ pw.println(prefix + " mLastReportedConfiguration=" + (mHasCachedConfiguration
+ ? ("(cached) " + mLastReportedConfiguration) : mLastReportedConfiguration));
final int stateFlags = mActivityStateFlags;
if (stateFlags != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1abe24e926fe..c91bec9fb0c9 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -116,7 +116,6 @@ 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;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -151,6 +150,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
@@ -616,11 +616,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
int mLastVisibleLayoutRotation = -1;
/**
- * Set when we need to report the orientation change to client to trigger a relayout.
- */
- boolean mReportOrientationChanged;
-
- /**
* How long we last kept the screen frozen.
*/
int mLastFreezeDuration;
@@ -1541,13 +1536,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|| configChanged
|| insetsChanged
|| dragResizingChanged
- || mReportOrientationChanged
|| shouldSendRedrawForSync()) {
ProtoLog.v(WM_DEBUG_RESIZE,
- "Resize reasons for w=%s: %s configChanged=%b "
- + "dragResizingChanged=%b reportOrientationChanged=%b",
+ "Resize reasons for w=%s: %s configChanged=%b dragResizingChanged=%b",
this, mWindowFrames.getInsetsChangedInfo(),
- configChanged, dragResizingChanged, mReportOrientationChanged);
+ configChanged, dragResizingChanged);
if (insetsChanged) {
mWindowFrames.setInsetsChanged(false);
@@ -2178,6 +2171,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (mActivityRecord != null) {
+ if (!mActivityRecord.mVisibleRequested) return;
if (mActivityRecord.allDrawn) {
// The allDrawn of activity is reset when the visibility is changed to visible, so
// the content should be ready if allDrawn is set.
@@ -3580,10 +3574,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mAnimatingExit = false;
ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=destroySurface win=%s", this);
- // Clear the flag so the buffer requested for the next new surface won't be dropped by
- // mistaking the surface size needs to update.
- mReportOrientationChanged = false;
-
if (useBLASTSync()) {
immediatelyNotifyBlastSync();
}
@@ -3900,12 +3890,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
ProtoLog.i(WM_DEBUG_ORIENTATION, "Resizing %s WITH DRAW PENDING", this);
}
- final boolean reportOrientation = mReportOrientationChanged;
// Always reset these states first, so if {@link IWindow#resized} fails, this
// window won't be added to {@link WindowManagerService#mResizingWindows} and set
// {@link #mOrientationChanging} to true again by {@link #updateResizingWindowIfNeeded}
// that may cause WINDOW_FREEZE_TIMEOUT because resizing the client keeps failing.
- mReportOrientationChanged = false;
mDragResizingChangeReported = true;
mWindowFrames.clearReportResizeHints();
@@ -3914,7 +3902,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final boolean syncRedraw = shouldSendRedrawForSync();
final boolean reportDraw = syncRedraw || drawPending;
final boolean isDragResizeChanged = isDragResizeChanged();
- final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged;
+ final boolean forceRelayout = syncRedraw || isDragResizeChanged;
final DisplayContent displayContent = getDisplayContent();
final boolean alwaysConsumeSystemBars =
displayContent.getDisplayPolicy().areSystemBarsForcedShownLw();
@@ -3941,7 +3929,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
mSyncSeqId, resizeMode);
- if (drawPending && reportOrientation && mOrientationChanging) {
+ if (drawPending && mOrientationChanging) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Requested redraw for orientation change: %s", this);
@@ -4366,12 +4354,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " mDestroying=" + mDestroying
+ " mRemoved=" + mRemoved);
}
- if (getOrientationChanging() || mAppFreezing || mReportOrientationChanged) {
+ if (getOrientationChanging() || mAppFreezing) {
pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
+ " configOrientationChanging="
+ (getLastReportedConfiguration().orientation != getConfiguration().orientation)
- + " mAppFreezing=" + mAppFreezing
- + " mReportOrientationChanged=" + mReportOrientationChanged);
+ + " mAppFreezing=" + mAppFreezing);
}
if (mLastFreezeDuration != 0) {
pw.print(prefix + "mLastFreezeDuration=");
@@ -5572,7 +5559,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
}
if (surfaceSizeChanged && mWinAnimator.getShown() && !canPlayMoveAnimation()
- && okToDisplay()) {
+ && okToDisplay() && mSyncState == SYNC_STATE_NONE) {
applyWithNextDraw(mSetSurfacePositionConsumer);
} else {
mSetSurfacePositionConsumer.accept(t);
@@ -6009,7 +5996,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// We could be more subtle with Integer.MAX_VALUE and track a seqId in the timeout.
finishDrawing(null, Integer.MAX_VALUE);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
- if (!useBLASTSync()) return;
}
@Override
@@ -6046,6 +6032,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mRedrawForSyncReported) {
return false;
}
+ if (mInRelayout) {
+ // The last sync seq id will return to the client, so there is no need to request the
+ // client to redraw.
+ return false;
+ }
return useBLASTSync();
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 5f43800bd9d5..fd379bf1d9f4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -139,6 +139,12 @@ class WindowSurfaceController {
"Destroying surface %s called by %s", this, Debug.getCallers(8));
try {
if (mSurfaceControl != null) {
+ if (mAnimator.mIsWallpaper && !mAnimator.mWin.mWindowRemovalAllowed
+ && !mAnimator.mWin.mRemoveOnExit) {
+ // The wallpaper surface should have the same lifetime as its window.
+ Slog.e(TAG, "Unexpected removing wallpaper surface of " + mAnimator.mWin
+ + " by " + Debug.getCallers(8));
+ }
t.remove(mSurfaceControl);
}
} catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index d2e56faa0914..0fa874448858 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -37,6 +36,7 @@ import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -363,12 +363,8 @@ class WindowToken extends WindowContainer<WindowState> {
@Override
void assignLayer(SurfaceControl.Transaction t, int layer) {
- if (windowType == TYPE_DOCK_DIVIDER) {
- // See {@link DisplayContent#mSplitScreenDividerAnchor}
- super.assignRelativeLayer(t,
- mDisplayContent.getDefaultTaskDisplayArea().getSplitScreenDividerAnchor(), 1);
- } else if (mRoundedCornerOverlay) {
- super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1);
+ if (mRoundedCornerOverlay) {
+ super.assignLayer(t, WindowManagerPolicy.SCREEN_DECOR_DISPLAY_OVERLAY_LAYER);
} else {
super.assignLayer(t, layer);
}
@@ -378,7 +374,7 @@ class WindowToken extends WindowContainer<WindowState> {
SurfaceControl.Builder makeSurface() {
final SurfaceControl.Builder builder = super.makeSurface();
if (mRoundedCornerOverlay) {
- builder.setParent(null);
+ builder.setParent(getDisplayContent().getOverlayLayer());
}
return builder;
}
@@ -569,13 +565,12 @@ class WindowToken extends WindowContainer<WindowState> {
* the same rotation.
*/
@Nullable
- SurfaceControl getOrCreateFixedRotationLeash() {
+ SurfaceControl getOrCreateFixedRotationLeash(@NonNull SurfaceControl.Transaction t) {
if (!mTransitionController.isShellTransitionsEnabled()) return null;
final int rotation = getRelativeDisplayRotation();
if (rotation == Surface.ROTATION_0) return mFixedRotationTransformLeash;
if (mFixedRotationTransformLeash != null) return mFixedRotationTransformLeash;
- final SurfaceControl.Transaction t = getSyncTransaction();
final SurfaceControl leash = makeSurface().setContainerLayer()
.setParent(getParentSurfaceControl())
.setName(getSurfaceControl() + " - rotation-leash")
@@ -591,6 +586,15 @@ class WindowToken extends WindowContainer<WindowState> {
return mFixedRotationTransformLeash;
}
+ /**
+ * @return the leash which represents this window as if it was non-rotated. Will be null if
+ * there isn't one.
+ */
+ @Nullable
+ SurfaceControl getFixedRotationLeash() {
+ return mFixedRotationTransformLeash;
+ }
+
void removeFixedRotationLeash() {
if (mFixedRotationTransformLeash == null) return;
final SurfaceControl.Transaction t = getSyncTransaction();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 0d49f5fffb4b..ec38f777593f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -181,10 +181,11 @@ cc_defaults {
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk",
+ "android.frameworks.stats-V2-ndk",
"android.system.suspend.control-V1-cpp",
"android.system.suspend.control.internal-cpp",
"android.system.suspend-V1-ndk",
+ "server_configurable_flags",
"service.incremental",
],
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 51bc99a693ff..85671105ec25 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -2,7 +2,7 @@
per-file com_android_server_lights_LightsService.cpp = michaelwr@google.com, santoscordon@google.com
# Input
-per-file com_android_server_input_InputManagerService.cpp = michaelwr@google.com, svv@google.com
+per-file com_android_server_input_* = file:/INPUT_OWNERS
# Power
per-file com_android_server_HardwarePropertiesManagerService.cpp = michaelwr@google.com, santoscordon@google.com
@@ -15,7 +15,6 @@ per-file Android.bp = file:platform/build/soong:/OWNERS
per-file com_android_server_Usb* = file:/services/usb/OWNERS
per-file com_android_server_Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
per-file com_android_server_hdmi_* = file:/core/java/android/hardware/hdmi/OWNERS
-per-file com_android_server_input_* = file:/core/java/android/hardware/input/OWNERS
per-file com_android_server_lights_* = file:/services/core/java/com/android/server/lights/OWNERS
per-file com_android_server_location_* = file:/location/java/android/location/OWNERS
per-file com_android_server_locksettings_* = file:/services/core/java/com/android/server/locksettings/OWNERS
@@ -23,8 +22,7 @@ per-file com_android_server_net_* = file:/services/core/java/com/android/server/
per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
-per-file com_android_server_se_* = file:/core/java/android/se/OWNERS
per-file com_android_server_security_* = file:/core/java/android/security/OWNERS
per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com \ No newline at end of file
+per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 287fb8219650..3de9d54d67b7 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -50,6 +50,7 @@
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <server_configurable_flags/get_flags.h>
#include <ui/Region.h>
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -70,7 +71,6 @@
using android::base::ParseUint;
using android::base::StringPrintf;
-using android::os::BlockUntrustedTouchesMode;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
@@ -87,6 +87,13 @@ namespace android {
// where the speed ranges from -7 to + 7 and is supplied by the user.
static const float POINTER_SPEED_EXPONENT = 1.0f / 4;
+// Category (=namespace) name for the input settings that are applied at boot time
+static const char* INPUT_NATIVE_BOOT = "input_native_boot";
+/**
+ * Feature flag name. This flag determines which VelocityTracker strategy is used by default.
+ */
+static const char* VELOCITYTRACKER_STRATEGY = "velocitytracker_strategy";
+
static struct {
jclass clazz;
jmethodID notifyConfigurationChanged;
@@ -100,7 +107,6 @@ static struct {
jmethodID notifySensorEvent;
jmethodID notifySensorAccuracy;
jmethodID notifyVibratorState;
- jmethodID notifyUntrustedTouch;
jmethodID filterInputEvent;
jmethodID interceptKeyBeforeQueueing;
jmethodID interceptMotionBeforeQueueingNonInteractive;
@@ -321,7 +327,6 @@ public:
void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
InputDeviceSensorAccuracy accuracy) override;
void notifyVibratorState(int32_t deviceId, bool isOn) override;
- void notifyUntrustedTouch(const std::string& obscuringPackage) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) override;
@@ -881,17 +886,6 @@ void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) {
}
}
-void NativeInputManager::notifyUntrustedTouch(const std::string& obscuringPackage) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("notifyUntrustedTouch - obscuringPackage=%s", obscuringPackage.c_str());
-#endif
- ATRACE_CALL();
- JNIEnv* env = jniEnv();
- jstring jPackage = env->NewStringUTF(obscuringPackage.c_str());
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyUntrustedTouch, jPackage);
- checkAndClearExceptionFromCallback(env, "notifyUntrustedTouch");
-}
-
void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken,
const sp<IBinder>& newToken) {
#if DEBUG_INPUT_DISPATCHER_POLICY
@@ -1686,13 +1680,6 @@ static void nativeSetMaximumObscuringOpacityForTouch(JNIEnv* env, jobject native
im->getInputManager()->getDispatcher().setMaximumObscuringOpacityForTouch(opacity);
}
-static void nativeSetBlockUntrustedTouchesMode(JNIEnv* env, jobject nativeImplObj, jint mode) {
- NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
-
- im->getInputManager()->getDispatcher().setBlockUntrustedTouchesMode(
- static_cast<BlockUntrustedTouchesMode>(mode));
-}
-
static jint nativeInjectInputEvent(JNIEnv* env, jobject nativeImplObj, jobject inputEventObj,
jboolean injectIntoUid, jint uid, jint syncMode,
jint timeoutMillis, jint policyFlags) {
@@ -2102,8 +2089,10 @@ static void nativeReloadDeviceAliases(JNIEnv* env, jobject nativeImplObj) {
static std::string dumpInputProperties() {
std::string out = "Input properties:\n";
const std::string strategy =
- sysprop::InputProperties::velocitytracker_strategy().value_or("default");
- out += " persist.input.velocitytracker.strategy = " + strategy + "\n";
+ server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
+ VELOCITYTRACKER_STRATEGY,
+ "default");
+ out += " velocitytracker_strategy (flag value) = " + strategy + "\n";
out += "\n";
return out;
}
@@ -2329,7 +2318,6 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"setInTouchMode", "(ZIIZ)Z", (void*)nativeSetInTouchMode},
{"setMaximumObscuringOpacityForTouch", "(F)V",
(void*)nativeSetMaximumObscuringOpacityForTouch},
- {"setBlockUntrustedTouchesMode", "(I)V", (void*)nativeSetBlockUntrustedTouchesMode},
{"injectInputEvent", "(Landroid/view/InputEvent;ZIIII)I", (void*)nativeInjectInputEvent},
{"verifyInputEvent", "(Landroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
(void*)nativeVerifyInputEvent},
@@ -2448,9 +2436,6 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.notifyVibratorState, clazz, "notifyVibratorState", "(IZ)V");
- GET_METHOD_ID(gServiceClassInfo.notifyUntrustedTouch, clazz, "notifyUntrustedTouch",
- "(Ljava/lang/String;)V");
-
GET_METHOD_ID(gServiceClassInfo.notifyNoFocusedWindowAnr, clazz, "notifyNoFocusedWindowAnr",
"(Landroid/view/InputApplicationHandle;)V");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index fd97db23f01a..054181dfa728 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -67,7 +67,6 @@ class DevicePolicyData {
private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set";
private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert";
private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
- private static final String TAG_PASSWORD_VALIDITY = "password-validity";
private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
private static final String TAG_PROTECTED_PACKAGES = "protected-packages";
private static final String TAG_BYPASS_ROLE_QUALIFICATIONS = "bypass-role-qualifications";
@@ -184,7 +183,7 @@ class DevicePolicyData {
/**
* Serializes DevicePolicyData object as XML.
*/
- static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) {
+ static boolean store(DevicePolicyData policyData, JournaledFile file) {
FileOutputStream stream = null;
File chooseForWrite = null;
try {
@@ -269,15 +268,6 @@ class DevicePolicyData {
out.endTag(null, "failed-password-attempts");
}
- // For FDE devices only, we save this flag so we can report on password sufficiency
- // before the user enters their password for the first time after a reboot. For
- // security reasons, we don't want to store the full set of active password metrics.
- if (isFdeDevice) {
- out.startTag(null, TAG_PASSWORD_VALIDITY);
- out.attributeBoolean(null, ATTR_VALUE, policyData.mPasswordValidAtLastCheckpoint);
- out.endTag(null, TAG_PASSWORD_VALIDITY);
- }
-
for (int i = 0; i < policyData.mAcceptedCaCertificates.size(); i++) {
out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
out.attribute(null, ATTR_NAME, policyData.mAcceptedCaCertificates.valueAt(i));
@@ -405,7 +395,7 @@ class DevicePolicyData {
* @param adminInfoSupplier function that queries DeviceAdminInfo from PackageManager
* @param ownerComponent device or profile owner component if any.
*/
- static void load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile,
+ static void load(DevicePolicyData policy, JournaledFile journaledFile,
Function<ComponentName, DeviceAdminInfo> adminInfoSupplier,
ComponentName ownerComponent) {
FileInputStream stream = null;
@@ -545,12 +535,6 @@ class DevicePolicyData {
policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
} else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) {
policy.mInitBundle = PersistableBundle.restoreFromXml(parser);
- } else if (TAG_PASSWORD_VALIDITY.equals(tag)) {
- if (isFdeDevice) {
- // This flag is only used for FDE devices
- policy.mPasswordValidAtLastCheckpoint =
- parser.getAttributeBoolean(null, ATTR_VALUE, false);
- }
} else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
policy.mPasswordTokenHandle = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 870257802608..f9b11b9ab254 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2670,11 +2670,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final DevicePolicyData policy = getUserData(userId);
if (who != null) {
ActiveAdmin admin = policy.mAdminMap.get(who);
- if (admin == null) {
- throw new SecurityException("No active admin " + who);
- }
- if (admin.getUid() != uid) {
- throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
+ if (admin == null || admin.getUid() != uid) {
+ throw new SecurityException(
+ "Admin " + who + " is not active or not owned by uid " + uid);
}
if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
return admin;
@@ -2882,10 +2880,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void saveSettingsLocked(int userHandle) {
- if (DevicePolicyData.store(
- getUserData(userHandle),
- makeJournaledFile(userHandle),
- !mInjector.storageManagerIsFileBasedEncryptionEnabled())) {
+ if (DevicePolicyData.store(getUserData(userHandle), makeJournaledFile(userHandle))) {
sendChangedNotification(userHandle);
}
invalidateBinderCaches();
@@ -2900,7 +2895,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
DevicePolicyData.load(policy,
- !mInjector.storageManagerIsFileBasedEncryptionEnabled(),
makeJournaledFile(userHandle),
component -> findAdmin(
component, userHandle, /* throwForMissingPermission= */ false),
@@ -3066,11 +3060,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// TODO(b/230841522) Make it static.
private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
@Override
- public boolean storageManagerIsFileBasedEncryptionEnabled() {
- return mInjector.storageManagerIsFileBasedEncryptionEnabled();
- }
-
- @Override
public JournaledFile makeDevicePoliciesJournaledFile(int userId) {
return DevicePolicyManagerService.this.makeJournaledFile(userId, DEVICE_POLICIES_XML);
}
@@ -3560,6 +3549,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ if (mInjector.getPackageManagerInternal().filterAppAccess(packageName, caller.getUid(),
+ userHandle)) {
+ return false;
+ }
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -9878,18 +9872,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getEncryptionStatusName(int encryptionStatus) {
switch (encryptionStatus) {
- case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
- return "inactive";
- case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY:
- return "block default key";
- case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
- return "block";
case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
return "per-user";
case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED:
return "unsupported";
- case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING:
- return "activating";
default:
return "unknown";
}
@@ -11767,6 +11753,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ap = getParentOfAdminIfRequired(getOrganizationOwnedProfileOwnerLocked(caller),
parent);
} else {
+ Preconditions.checkCallAuthorization(!isFinancedDeviceOwner(caller));
ap = getParentOfAdminIfRequired(getProfileOwnerOrDeviceOwnerLocked(caller), parent);
}
@@ -12517,8 +12504,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.setContentIntent(locationSettingsIntent)
.setAutoCancel(true)
.build();
- mInjector.getNotificationManager().notify(SystemMessage.NOTE_LOCATION_CHANGED,
- notification);
+ mHandler.post(() -> mInjector.getNotificationManager().notify(
+ SystemMessage.NOTE_LOCATION_CHANGED, notification));
}
private String getLocationChangedTitle() {
@@ -13953,8 +13940,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
granted = PackageManager.PERMISSION_GRANTED;
}
} catch (NameNotFoundException e) {
- throw new RemoteException("Cannot check if " + permission
- + "is a runtime permission", e, false, true);
+ // Package does not exit
+ return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
}
}
int permFlags = mInjector.getPackageManager().getPermissionFlags(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index 7b7a454fc945..147474907f29 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -29,11 +29,6 @@ import java.util.function.Function;
*/
public interface PolicyUpgraderDataProvider {
/**
- * Returns true if the storage manager indicates file-based encryption is enabled.
- */
- boolean storageManagerIsFileBasedEncryptionEnabled();
-
- /**
* Returns the journaled policies file for a given user.
*/
JournaledFile makeDevicePoliciesJournaledFile(int userId);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 253851cdbf68..808133164cd1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -222,7 +222,6 @@ public class PolicyVersionUpgrader {
int userId, int loadVersion, ComponentName ownerComponent) {
DevicePolicyData policy = new DevicePolicyData(userId);
DevicePolicyData.load(policy,
- !mProvider.storageManagerIsFileBasedEncryptionEnabled(),
mProvider.makeDevicePoliciesJournaledFile(userId),
mProvider.getAdminInfoSupplier(userId),
ownerComponent);
@@ -230,10 +229,7 @@ public class PolicyVersionUpgrader {
}
private boolean writeDataForUser(int userId, DevicePolicyData policy) {
- return DevicePolicyData.store(
- policy,
- mProvider.makeDevicePoliciesJournaledFile(userId),
- !mProvider.storageManagerIsFileBasedEncryptionEnabled());
+ return DevicePolicyData.store(policy, mProvider.makeDevicePoliciesJournaledFile(userId));
}
private JournaledFile getVersionFile() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ef311c249c5f..3313f60a4efd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -79,7 +79,6 @@ import android.os.storage.IStorageManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.server.ServerProtoEnums;
-import android.sysprop.VoldProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -197,6 +196,7 @@ import com.android.server.telecom.TelecomLoaderService;
import com.android.server.testharness.TestHarnessModeService;
import com.android.server.textclassifier.TextClassificationManagerService;
import com.android.server.textservices.TextServicesManagerService;
+import com.android.server.timedetector.NetworkTimeUpdateService;
import com.android.server.tracing.TracingServiceProxy;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
@@ -238,9 +238,6 @@ public final class SystemServer implements Dumpable {
private static final String TAG = "SystemServer";
- private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
- private static final String ENCRYPTED_STATE = "1";
-
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
@@ -338,6 +335,8 @@ public final class SystemServer implements Dumpable {
"com.android.server.contentcapture.ContentCaptureManagerService";
private static final String TRANSLATION_MANAGER_SERVICE_CLASS =
"com.android.server.translation.TranslationManagerService";
+ private static final String SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS =
+ "com.android.server.selectiontoolbar.SelectionToolbarManagerService";
private static final String MUSIC_RECOGNITION_MANAGER_SERVICE_CLASS =
"com.android.server.musicrecognition.MusicRecognitionManagerService";
private static final String SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS =
@@ -460,7 +459,6 @@ public final class SystemServer implements Dumpable {
private DataLoaderManagerService mDataLoaderManagerService;
private long mIncrementalServiceHandle = 0;
- private boolean mOnlyCore;
private boolean mFirstBoot;
private final int mStartCount;
private final boolean mRuntimeRestart;
@@ -654,19 +652,14 @@ public final class SystemServer implements Dumpable {
mFactoryTestMode = FactoryTest.getMode();
// Record process start information.
- // Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
- // one for the password screen, second for the actual boot.
mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();
Process.setStartTimes(mRuntimeStartElapsedTime, mRuntimeStartUptime,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
- // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
- // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
- // TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
- // sys.boot_completed is set. Fix it.
- mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
+ // Remember if it's runtime restart or reboot.
+ mRuntimeRestart = mStartCount > 1;
}
@Override
@@ -1202,16 +1195,6 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
t.traceEnd();
- // Only run "core" apps if we're encrypting the device.
- String cryptState = VoldProperties.decrypt().orElse("");
- if (ENCRYPTING_STATE.equals(cryptState)) {
- Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
- mOnlyCore = true;
- } else if (ENCRYPTED_STATE.equals(cryptState)) {
- Slog.w(TAG, "Device encrypted - only parsing core apps");
- mOnlyCore = true;
- }
-
// Start the package manager.
if (!mRuntimeRestart) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
@@ -1232,7 +1215,7 @@ public final class SystemServer implements Dumpable {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
Pair<PackageManagerService, IPackageManager> pmsPair = PackageManagerService.main(
mSystemContext, installer, domainVerificationService,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
+ mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
mPackageManagerService = pmsPair.first;
iPackageManager = pmsPair.second;
} finally {
@@ -1255,21 +1238,17 @@ public final class SystemServer implements Dumpable {
}
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
- // Note: this isn't needed during decryption (we don't have /data anyways).
- if (!mOnlyCore) {
- boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
- false);
- if (!disableOtaDexopt) {
- t.traceBegin("StartOtaDexOptService");
- try {
- Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
- OtaDexoptService.main(mSystemContext, mPackageManagerService);
- } catch (Throwable e) {
- reportWtf("starting OtaDexOptService", e);
- } finally {
- Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
- t.traceEnd();
- }
+ boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false);
+ if (!disableOtaDexopt) {
+ t.traceBegin("StartOtaDexOptService");
+ try {
+ Watchdog.getInstance().pauseWatchingCurrentThread("moveab");
+ OtaDexoptService.main(mSystemContext, mPackageManagerService);
+ } catch (Throwable e) {
+ reportWtf("starting OtaDexOptService", e);
+ } finally {
+ Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
+ t.traceEnd();
}
}
@@ -1583,7 +1562,7 @@ public final class SystemServer implements Dumpable {
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
- wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
+ wm = WindowManagerService.main(context, inputManager, !mFirstBoot,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
@@ -1757,19 +1736,16 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
-
- if (!mOnlyCore) {
- t.traceBegin("UpdatePackagesIfNeeded");
- try {
- Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
- mPackageManagerService.updatePackagesIfNeeded();
- } catch (Throwable e) {
- reportWtf("update packages", e);
- } finally {
- Watchdog.getInstance().resumeWatchingCurrentThread("dexopt");
- }
- t.traceEnd();
+ t.traceBegin("UpdatePackagesIfNeeded");
+ try {
+ Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
+ mPackageManagerService.updatePackagesIfNeeded();
+ } catch (Throwable e) {
+ reportWtf("update packages", e);
+ } finally {
+ Watchdog.getInstance().resumeWatchingCurrentThread("dexopt");
}
+ t.traceEnd();
t.traceBegin("PerformFstrimIfNeeded");
try {
@@ -2308,13 +2284,9 @@ public final class SystemServer implements Dumpable {
t.traceEnd();
// timezone.RulesManagerService will prevent a device starting up if the chain of trust
- // required for safe time zone updates might be broken. RuleManagerService cannot do
- // this check when mOnlyCore == true, so we don't enable the service in this case.
- // This service requires that JobSchedulerService is already started when it starts.
- final boolean startRulesManagerService =
- !mOnlyCore && context.getResources().getBoolean(
- R.bool.config_enableUpdateableTimeZoneRules);
- if (startRulesManagerService) {
+ // required for safe time zone updates might be broken. This service requires that
+ // JobSchedulerService is already started when it starts.
+ if (context.getResources().getBoolean(R.bool.config_enableUpdateableTimeZoneRules)) {
t.traceBegin("StartTimeZoneRulesManagerService");
mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS);
t.traceEnd();
@@ -2634,6 +2606,11 @@ public final class SystemServer implements Dumpable {
Slog.d(TAG, "TranslationService not defined by OEM");
}
+ // Selection toolbar service
+ t.traceBegin("StartSelectionToolbarManagerService");
+ mSystemServiceManager.startService(SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
// NOTE: ClipboardService depends on ContentCapture and Autofill
t.traceBegin("StartClipboardService");
mSystemServiceManager.startService(ClipboardService.class);
@@ -2714,8 +2691,8 @@ public final class SystemServer implements Dumpable {
t.traceBegin("MakeDisplayManagerServiceReady");
try {
- // TODO: use boot phase and communicate these flags some other way
- mDisplayManagerService.systemReady(safeMode, mOnlyCore);
+ // TODO: use boot phase and communicate this flag some other way
+ mDisplayManagerService.systemReady(safeMode);
} catch (Throwable e) {
reportWtf("making Display Manager Service ready", e);
}
@@ -2823,7 +2800,7 @@ public final class SystemServer implements Dumpable {
// be completed before allowing 3rd party
final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
Future<?> webviewPrep = null;
- if (!mOnlyCore && mWebViewUpdateService != null) {
+ if (mWebViewUpdateService != null) {
webviewPrep = SystemServerInitThreadPool.submit(() -> {
Slog.i(TAG, WEBVIEW_PREPARATION);
TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 5dc048b9d7c6..df1d244ab879 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -171,7 +171,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private void mockCrossProfileAppRequestsInteractAcrossProfiles() throws Exception {
final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
- when(mIPackageManager.getAppOpPermissionPackages(permissionName))
+ when(mIPackageManager.getAppOpPermissionPackages(eq(permissionName), anyInt()))
.thenReturn(new String[] {CROSS_PROFILE_APP_PACKAGE_NAME});
}
@@ -488,7 +488,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private void mockCrossProfileAppDoesNotRequestInteractAcrossProfiles() throws Exception {
final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
- when(mIPackageManager.getAppOpPermissionPackages(permissionName))
+ when(mIPackageManager.getAppOpPermissionPackages(eq(permissionName), anyInt()))
.thenReturn(new String[] {});
}
diff --git a/services/selectiontoolbar/Android.bp b/services/selectiontoolbar/Android.bp
new file mode 100644
index 000000000000..cc6405f97bc3
--- /dev/null
+++ b/services/selectiontoolbar/Android.bp
@@ -0,0 +1,22 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "services.selectiontoolbar-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.selectiontoolbar",
+ defaults: ["platform_service_defaults"],
+ srcs: [":services.selectiontoolbar-sources"],
+ libs: ["services.core"],
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 479ef8e5f188..cdb6324988be 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -30,6 +30,7 @@ android_test {
"compatibility-device-util-axt",
"androidx.test.runner",
"truth-prebuilt",
+ "Harrier",
],
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
index 2039aaa20945..0395aa8a1db6 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
@@ -16,7 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.appenumeration">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.server.pm.test.appenumeration">
+
+ <queries>
+ <package android:name="com.android.appenumeration.crossuserpackagevisibility" />
+ </queries>
+
+ <!-- It's merged from Harrier library. Remove it since this test should not hold it. -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:node="remove" />
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.appenumeration"
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
index 67efa142aac5..f48974a3b8e0 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
@@ -34,6 +34,7 @@
<option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" />
<option name="push" value="AppEnumerationHasAppOpPermissionTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationHasAppOpPermissionTestApp.apk" />
<option name="push" value="AppEnumerationSharedUserTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSharedUserTestApp.apk" />
+ <option name="push" value="AppEnumerationCrossUserPackageVisibilityTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationCrossUserPackageVisibilityTestApp.apk" />
</target_preparer>
<option name="test-tag" value="AppEnumerationInternalTest" />
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index ab004bea553e..08cea06fd314 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -24,6 +24,7 @@ import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
import android.os.Process;
+import android.os.UserHandle;
import androidx.test.runner.AndroidJUnit4;
@@ -102,7 +103,7 @@ public class AppEnumerationInternalTests {
installPackage(HAS_APPOP_PERMISSION_APK_PATH, true /* forceQueryable */);
final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
- PERMISSION_REQUEST_INSTALL_PACKAGES);
+ PERMISSION_REQUEST_INSTALL_PACKAGES, UserHandle.myUserId());
assertThat(packageNames).asList().contains(TARGET_HAS_APPOP_PERMISSION);
}
@@ -112,7 +113,7 @@ public class AppEnumerationInternalTests {
installPackage(HAS_APPOP_PERMISSION_APK_PATH, false /* forceQueryable */);
final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
- PERMISSION_REQUEST_INSTALL_PACKAGES);
+ PERMISSION_REQUEST_INSTALL_PACKAGES, UserHandle.myUserId());
assertThat(packageNames).asList().doesNotContain(TARGET_HAS_APPOP_PERMISSION);
}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
new file mode 100644
index 000000000000..e33ca7775e22
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2022 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.pm.test.appenumeration;
+
+import static android.Manifest.permission.CLEAR_APP_USER_DATA;
+import static android.Manifest.permission.DELETE_PACKAGES;
+import static android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS;
+import static android.Manifest.permission.MOVE_PACKAGE;
+import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.AppGlobals;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.KeySet;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
+import com.android.bedstead.nene.users.UserReference;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Verify that app without holding the {@link android.Manifest.permission.INTERACT_ACROSS_USERS}
+ * can't detect the existence of another app in the different users on the device via the
+ * side channel attacks.
+ */
+@EnsureHasSecondaryUser
+@RunWith(BedsteadJUnit4.class)
+public class CrossUserPackageVisibilityTests {
+ private static final String TEST_DATA_DIR = "/data/local/tmp/appenumerationtests";
+ private static final String CROSS_USER_TEST_PACKAGE_NAME =
+ "com.android.appenumeration.crossuserpackagevisibility";
+ private static final String SHARED_USER_TEST_PACKAGE_NAME =
+ "com.android.appenumeration.shareduid";
+ private static final String HAS_APPOP_PERMISSION_PACKAGE_NAME =
+ "com.android.appenumeration.hasappoppermission";
+
+ private static final File CROSS_USER_TEST_APK_FILE =
+ new File(TEST_DATA_DIR, "AppEnumerationCrossUserPackageVisibilityTestApp.apk");
+ private static final File SHARED_USER_TEST_APK_FILE =
+ new File(TEST_DATA_DIR, "AppEnumerationSharedUserTestApp.apk");
+ private static final File HAS_APPOP_PERMISSION_APK_FILE =
+ new File(TEST_DATA_DIR, "AppEnumerationHasAppOpPermissionTestApp.apk");
+
+ private static final String ACTION_CROSS_USER_TEST =
+ "com.android.appenumeration.action.CROSS_USER_TEST";
+ private static final String PERMISSION_REQUEST_INSTALL_PACKAGES =
+ "android.permission.REQUEST_INSTALL_PACKAGES";
+ private static final ComponentName TEST_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ CROSS_USER_TEST_PACKAGE_NAME, "com.android.appenumeration.testapp.DummyActivity");
+
+ private static final long DEFAULT_TIMEOUT_MS = 5000;
+
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private Instrumentation mInstrumentation;
+ private IPackageManager mIPackageManager;
+ private Context mContext;
+ private UserReference mCurrentUser;
+ private UserReference mOtherUser;
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mIPackageManager = AppGlobals.getPackageManager();
+ mContext = mInstrumentation.getContext();
+
+ // Get another user
+ final UserReference primaryUser = sDeviceState.primaryUser();
+ if (primaryUser.id() == UserHandle.myUserId()) {
+ mCurrentUser = primaryUser;
+ mOtherUser = sDeviceState.secondaryUser();
+ } else {
+ mCurrentUser = sDeviceState.secondaryUser();
+ mOtherUser = primaryUser;
+ }
+
+ uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
+ uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
+ uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testGetSplashScreenTheme_withCrossUserId() {
+ final int crossUserId = UserHandle.myUserId() + 1;
+ assertThrows(SecurityException.class,
+ () -> mIPackageManager.getSplashScreenTheme(
+ mInstrumentation.getContext().getPackageName(), crossUserId));
+ }
+
+ @Test
+ public void testIsPackageSignedByKeySet_cannotDetectCrossUserPkg() throws Exception {
+ final KeySet keySet = mIPackageManager.getSigningKeySet(mContext.getPackageName());
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySet(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySet(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+ }
+
+ @Test
+ public void testIsPackageSignedByKeySetExactly_cannotDetectCrossUserPkg() throws Exception {
+ final KeySet keySet = mIPackageManager.getSigningKeySet(mContext.getPackageName());
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySetExactly(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySetExactly(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+ }
+
+ @Test
+ public void testGetSigningKeySet_cannotDetectCrossUserPkg() {
+ final IllegalArgumentException e1 = assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.getSigningKeySet(CROSS_USER_TEST_PACKAGE_NAME));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ final IllegalArgumentException e2 = assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.getSigningKeySet(CROSS_USER_TEST_PACKAGE_NAME));
+ assertThat(e1.getMessage()).isEqualTo(e2.getMessage());
+ }
+
+ @Test
+ public void testGetKeySetByAlias_cannotDetectCrossUserPkg() {
+ final String alias = CROSS_USER_TEST_PACKAGE_NAME + ".alias";
+ final IllegalArgumentException e1 = assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.getKeySetByAlias(CROSS_USER_TEST_PACKAGE_NAME, alias));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ final IllegalArgumentException e2 = assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.getKeySetByAlias(CROSS_USER_TEST_PACKAGE_NAME, alias));
+ assertThat(e1.getMessage()).isEqualTo(e2.getMessage());
+ }
+
+ @Test
+ public void testGetFlagsForUid_cannotDetectCrossUserPkg() throws Exception {
+ installPackage(CROSS_USER_TEST_APK_FILE);
+ final int uid = mContext.getPackageManager().getPackageUid(
+ CROSS_USER_TEST_PACKAGE_NAME, PackageManager.PackageInfoFlags.of(0));
+
+ uninstallPackageForUser(CROSS_USER_TEST_PACKAGE_NAME, mCurrentUser);
+
+ assertThat(mIPackageManager.getFlagsForUid(uid)).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetUidForSharedUser_cannotDetectSharedUserPkg() throws Exception {
+ assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
+ .isEqualTo(Process.INVALID_UID);
+
+ installPackageForUser(SHARED_USER_TEST_APK_FILE, mOtherUser, true /* forceQueryable */);
+
+ assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
+ .isEqualTo(Process.INVALID_UID);
+ }
+
+ @Test
+ public void testClearApplicationUserData_cannotDetectStubPkg() throws Exception {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(CLEAR_APP_USER_DATA);
+ assertThat(clearApplicationUserData(CROSS_USER_TEST_PACKAGE_NAME)).isFalse();
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThat(clearApplicationUserData(CROSS_USER_TEST_PACKAGE_NAME)).isFalse();
+ }
+
+ @Test
+ public void testGetBlockUninstallForUser_cannotDetectStubPkg() throws Exception {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(DELETE_PACKAGES);
+ assertThat(mIPackageManager.setBlockUninstallForUser(
+ CROSS_USER_TEST_PACKAGE_NAME, true, mCurrentUser.id())).isTrue();
+ try {
+ assertThat(mIPackageManager.getBlockUninstallForUser(
+ CROSS_USER_TEST_PACKAGE_NAME, mCurrentUser.id())).isFalse();
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThat(mIPackageManager.getBlockUninstallForUser(
+ CROSS_USER_TEST_PACKAGE_NAME, mCurrentUser.id())).isFalse();
+ } finally {
+ assertThat(mIPackageManager.setBlockUninstallForUser(
+ CROSS_USER_TEST_PACKAGE_NAME, false, mCurrentUser.id())).isTrue();
+ }
+ }
+
+ @Test
+ public void testMovePackage_cannotDetectStubPkg() throws Exception {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ MOVE_PACKAGE, MOUNT_UNMOUNT_FILESYSTEMS);
+ assertThat(movePackage(CROSS_USER_TEST_PACKAGE_NAME, null /* volumeUuid */))
+ .isEqualTo(MOVE_FAILED_DOESNT_EXIST);
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThat(movePackage(CROSS_USER_TEST_PACKAGE_NAME, null /* volumeUuid */))
+ .isEqualTo(MOVE_FAILED_DOESNT_EXIST);
+ }
+
+ @Test
+ public void testActivitySupportsIntentAsUser_cannotDetectStubPkg() throws Exception {
+ assertThat(mIPackageManager.activitySupportsIntentAsUser(
+ TEST_ACTIVITY_COMPONENT_NAME,
+ new Intent(ACTION_CROSS_USER_TEST),
+ null,
+ mCurrentUser.id())).isFalse();
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThat(mIPackageManager.activitySupportsIntentAsUser(
+ TEST_ACTIVITY_COMPONENT_NAME,
+ new Intent(ACTION_CROSS_USER_TEST),
+ null,
+ mCurrentUser.id())).isFalse();
+ }
+
+ @Test
+ public void testGetAppOpPermissionPackages_cannotDetectPkg() throws Exception {
+ final int userId = mCurrentUser.id();
+ assertThat(mIPackageManager
+ .getAppOpPermissionPackages(PERMISSION_REQUEST_INSTALL_PACKAGES, userId))
+ .asList().doesNotContain(HAS_APPOP_PERMISSION_PACKAGE_NAME);
+
+ installPackageForUser(HAS_APPOP_PERMISSION_APK_FILE, mOtherUser, true /* forceQueryable */);
+
+ assertThat(mIPackageManager
+ .getAppOpPermissionPackages(PERMISSION_REQUEST_INSTALL_PACKAGES, userId))
+ .asList().doesNotContain(HAS_APPOP_PERMISSION_PACKAGE_NAME);
+ }
+
+ private boolean clearApplicationUserData(String packageName) throws Exception {
+ final AtomicInteger result = new AtomicInteger(-1);
+ final IPackageDataObserver localObserver = new IPackageDataObserver.Stub() {
+ @Override
+ public void onRemoveCompleted(String removedPkgName, boolean succeeded)
+ throws RemoteException {
+ if (removedPkgName.equals(packageName)) {
+ result.set(succeeded ? 1 : 0);
+ result.notifyAll();
+ }
+ }
+ };
+ mIPackageManager.clearApplicationUserData(packageName, localObserver, mCurrentUser.id());
+ TestUtils.waitOn(result, () -> result.get() != -1, DEFAULT_TIMEOUT_MS,
+ "clearApplicationUserData: " + packageName);
+ return result.get() == 1;
+ }
+
+ private int movePackage(String packageName, String volumeUuid) throws Exception {
+ final int moveId = mIPackageManager.movePackage(packageName, volumeUuid);
+ PollingCheck.check(
+ "Waiting for the package " + packageName + " moving timeout",
+ DEFAULT_TIMEOUT_MS,
+ () -> PackageManager.isMoveStatusFinished(mIPackageManager.getMoveStatus(moveId)));
+ return mIPackageManager.getMoveStatus(moveId);
+ }
+
+ private static void installPackage(File apk) {
+ installPackageForUser(apk, null, false /* forceQueryable */);
+ }
+
+ private static void installPackageForUser(File apk, UserReference user) {
+ installPackageForUser(apk, user, false /* forceQueryable */);
+ }
+
+ private static void installPackageForUser(File apk, UserReference user,
+ boolean forceQueryable) {
+ assertThat(apk.exists()).isTrue();
+ final StringBuilder cmd = new StringBuilder("pm install -t ");
+ if (forceQueryable) {
+ cmd.append("--force-queryable ");
+ }
+ if (user != null) {
+ cmd.append("--user ").append(user.id()).append(" ");
+ }
+ cmd.append(apk.getPath());
+ final String result = runShellCommand(cmd.toString());
+ assertThat(result.trim()).contains("Success");
+ }
+
+ private static void uninstallPackage(String packageName) {
+ uninstallPackageForUser(packageName, null /* user */);
+ }
+
+ private static void uninstallPackageForUser(String packageName, UserReference user) {
+ final StringBuilder cmd = new StringBuilder("pm uninstall ");
+ if (user != null) {
+ cmd.append("--user ").append(user.id()).append(" ");
+ }
+ cmd.append(packageName);
+ runShellCommand(cmd.toString());
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
index e0f83272f7a8..99211062964e 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
@@ -62,3 +62,17 @@ android_test_helper_app {
test_suites: ["device-tests"],
platform_apis: true,
}
+
+android_test_helper_app {
+ name: "AppEnumerationCrossUserPackageVisibilityTestApp",
+ srcs: ["src/**/*.java"],
+ manifest: "AndroidManifest-crossUserPackageVisibility.xml",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+ platform_apis: true,
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
new file mode 100644
index 000000000000..c36d77455e80
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.appenumeration.crossuserpackagevisibility">
+ <application android:testOnly="true">
+ <activity android:name="com.android.appenumeration.testapp.DummyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.appenumeration.action.CROSS_USER_TEST"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 53adc2fb00e6..462c5801e952 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -40,5 +40,4 @@ android_test_helper_app {
"androidx.test.rules",
"truth-prebuilt",
],
- platform_apis: true,
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 7a9c41256d61..728fc6c8e536 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -200,6 +200,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::isExternalStorage,
AndroidPackage::isExtractNativeLibs,
AndroidPackage::isFactoryTest,
+ AndroidPackage::isApex,
AndroidPackage::isForceQueryable,
AndroidPackage::isFullBackupOnly,
AndroidPackage::isGame,
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index a2e813aed720..82334f29099d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -59,6 +59,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageStateInternal;
import org.junit.After;
import org.junit.Before;
@@ -136,14 +137,17 @@ public class AppOpsServiceTest {
.spyStatic(Settings.Global.class)
.startMocking();
- // Mock LocalServices.getService(PackageManagerInternal.class).getPackage dependency
- // needed by AppOpsService
+ // Mock LocalServices.getService(PackageManagerInternal.class).getPackageStateInternal
+ // and getPackage dependency needed by AppOpsService
PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
+ PackageStateInternal mockMyPSInternal = mock(PackageStateInternal.class);
AndroidPackage mockMyPkg = mock(AndroidPackage.class);
when(mockMyPkg.isPrivileged()).thenReturn(false);
when(mockMyPkg.getUid()).thenReturn(mMyUid);
when(mockMyPkg.getAttributions()).thenReturn(Collections.emptyList());
+ when(mockPackageManagerInternal.getPackageStateInternal(sMyPackageName))
+ .thenReturn(mockMyPSInternal);
when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
doReturn(mockPackageManagerInternal).when(
() -> LocalServices.getService(PackageManagerInternal.class));
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 617321beadd2..7755552bcad2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -558,6 +558,40 @@ public class LocalDisplayAdapterTest {
}
@Test
+ public void testAfterDisplayStateChanges_committedSetAfterState() throws Exception {
+ FakeDisplay display = new FakeDisplay(PORT_A);
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+
+ // Turn off.
+ Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_OFF, 0,
+ 0);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+ mListener.changedDisplays.clear();
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isNotEqualTo(
+ Display.STATE_OFF);
+ verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
+
+ // Execute powerstate change.
+ changeStateRunnable.run();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+
+ // Verify that committed triggered a new change event and is set correctly.
+ verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isEqualTo(
+ Display.STATE_OFF);
+ }
+
+ @Test
public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);
display.dynamicInfo.gameContentTypeSupported = true;
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index b9551999cacb..bc9e9bb9bce8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -38,7 +38,6 @@ import com.android.internal.R;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -191,7 +190,6 @@ public class DisplayWhiteBalanceTintControllerTest {
* Matrix should match the precalculated one for given cct and display primaries.
*/
@Test
- @Ignore
public void displayWhiteBalance_validateTransformMatrix() {
DisplayPrimaries displayPrimaries = new DisplayPrimaries();
displayPrimaries.red = new CieXyz();
@@ -226,12 +224,12 @@ public class DisplayWhiteBalanceTintControllerTest {
float[] matrixDwb = mDisplayWhiteBalanceTintController.getMatrix();
final float[] expectedMatrixDwb = {
- 0.962880f, -0.001780f, -0.000158f, 0.0f,
- 0.035765f, 0.929988f, 0.000858f, 0.0f,
- 0.001354f, -0.000470f, 0.948327f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f
+ 0.971848f, -0.001421f, 0.000491f, 0.0f,
+ 0.028193f, 0.945798f, 0.003207f, 0.0f,
+ -0.000042f, -0.000989f, 0.988659f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
};
- assertArrayEquals("Unexpected DWB matrix", matrixDwb, expectedMatrixDwb,
+ assertArrayEquals("Unexpected DWB matrix", expectedMatrixDwb, matrixDwb,
1e-6f /* tolerance */);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt
new file mode 100644
index 000000000000..d25649edb816
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BroadcastHelperTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 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.pm
+
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+class BroadcastHelperTest {
+
+ companion object {
+ const val TEST_PACKAGE_1 = "com.android.test.package1"
+ const val TEST_PACKAGE_2 = "com.android.test.package2"
+ const val TEST_UID_1 = 10100
+ const val TEST_UID_2 = 10101
+ const val TEST_USER_ID = 0
+ }
+
+ lateinit var broadcastHelper: BroadcastHelper
+ lateinit var packagesToChange: Array<String>
+ lateinit var uidsToChange: IntArray
+
+ @Mock
+ lateinit var snapshot: Computer
+
+ @Rule
+ @JvmField
+ val rule = MockSystemRule()
+
+ @Before
+ open fun setup() {
+ MockitoAnnotations.initMocks(this)
+ rule.system().stageNominalSystemState()
+ broadcastHelper = BroadcastHelper(rule.mocks().injector)
+ packagesToChange = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ uidsToChange = intArrayOf(TEST_UID_1, TEST_UID_2)
+ }
+
+ @Test
+ fun getBroadcastParams_withSameVisibilityAllowList_shouldGroup() {
+ val allowList = intArrayOf(10001, 10002, 10003)
+ mockVisibilityAllowList(TEST_PACKAGE_1, allowList)
+ mockVisibilityAllowList(TEST_PACKAGE_2, allowList)
+
+ val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
+ snapshot, packagesToChange, uidsToChange, TEST_USER_ID)
+
+ assertThat(broadcastParams).hasSize(1)
+ assertThat(broadcastParams[0].packageNames).asList().containsExactlyElementsIn(
+ packagesToChange.toCollection(ArrayList()))
+ assertThat(broadcastParams[0].uids).asList().containsExactlyElementsIn(
+ uidsToChange.toCollection(ArrayList()))
+ }
+
+ @Test
+ fun getBroadcastParams_withDifferentVisibilityAllowList_shouldNotGroup() {
+ val allowList1 = intArrayOf(10001, 10002, 10003)
+ val allowList2 = intArrayOf(10001, 10002, 10007)
+ mockVisibilityAllowList(TEST_PACKAGE_1, allowList1)
+ mockVisibilityAllowList(TEST_PACKAGE_2, allowList2)
+
+ val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
+ snapshot, packagesToChange, uidsToChange, TEST_USER_ID)
+
+ assertThat(broadcastParams).hasSize(2)
+ broadcastParams.forEachIndexed { i, params ->
+ val changedPackages = params.packageNames
+ val changedUids = params.uids
+ assertThat(changedPackages[0]).isEqualTo(packagesToChange[i])
+ assertThat(changedUids[0]).isEqualTo(uidsToChange[i])
+ }
+ }
+
+ @Test
+ fun getBroadcastParams_withNullVisibilityAllowList_shouldNotGroup() {
+ val allowList = intArrayOf(10001, 10002, 10003)
+ mockVisibilityAllowList(TEST_PACKAGE_1, allowList)
+ mockVisibilityAllowList(TEST_PACKAGE_2, null)
+
+ val broadcastParams: List<BroadcastParams> = broadcastHelper.getBroadcastParams(
+ snapshot, packagesToChange, uidsToChange, TEST_USER_ID)
+
+ assertThat(broadcastParams).hasSize(2)
+ broadcastParams.forEachIndexed { i, params ->
+ val changedPackages = params.packageNames
+ val changedUids = params.uids
+ assertThat(changedPackages[0]).isEqualTo(packagesToChange[i])
+ assertThat(changedUids[0]).isEqualTo(uidsToChange[i])
+ }
+ }
+
+ private fun mockVisibilityAllowList(pkgName: String, list: IntArray?) {
+ whenever(snapshot.getVisibilityAllowList(pkgName, TEST_USER_ID))
+ .thenReturn(list ?: IntArray(0))
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
index e30f3d26119f..69584e067de4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
@@ -59,7 +59,6 @@ class DeletePackageHelperTest {
private fun createPackageManagerService(): PackageManagerService {
return spy(PackageManagerService(rule.mocks().injector,
- false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /*isEngBuild*/,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
index cf6c82f23730..d8770e510375 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
@@ -29,6 +29,7 @@ import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@RunWith(JUnit4::class)
@@ -192,4 +193,66 @@ class DistractingPackageHelperTest : PackageHelperTestBase() {
Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), nullable(), anyInt(),
nullable(), nullable(), any(), nullable(), nullable(), nullable())
}
+
+ @Test
+ fun sendDistractingPackagesChanged_withSameVisibilityAllowList() {
+ distractingPackageHelper.sendDistractingPackagesChanged(pms.snapshotComputer(),
+ packagesToChange, uidsToChange, TEST_USER_ID,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS)
+ testHandler.flush()
+ verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED),
+ nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
+ nullable(), nullable(), nullable())
+
+ var changedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ var changedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
+ assertThat(changedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ assertThat(changedUids).asList().containsExactly(
+ packageSetting1.appId, packageSetting2.appId)
+ }
+
+ @Test
+ fun sendDistractingPackagesChanged_withDifferentVisibilityAllowList() {
+ mockDividedSeparatedBroadcastList(
+ intArrayOf(10001, 10002, 10003), intArrayOf(10001, 10002, 10007))
+
+ distractingPackageHelper.sendDistractingPackagesChanged(pms.snapshotComputer(),
+ packagesToChange, uidsToChange, TEST_USER_ID,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS)
+ testHandler.flush()
+ verify(broadcastHelper, times(2)).sendPackageBroadcast(
+ eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), bundleCaptor.capture(),
+ anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
+
+ bundleCaptor.allValues.forEachIndexed { i, it ->
+ var changedPackages = it.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ var changedUids = it.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
+ assertThat(changedPackages?.size).isEqualTo(1)
+ assertThat(changedUids?.size).isEqualTo(1)
+ assertThat(changedPackages?.get(0)).isEqualTo(packagesToChange[i])
+ assertThat(changedUids?.get(0)).isEqualTo(uidsToChange[i])
+ }
+ }
+
+ @Test
+ fun sendDistractingPackagesChanged_withNullVisibilityAllowList() {
+ mockDividedSeparatedBroadcastList(intArrayOf(10001, 10002, 10003), null)
+
+ distractingPackageHelper.sendDistractingPackagesChanged(pms.snapshotComputer(),
+ packagesToChange, uidsToChange, TEST_USER_ID,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS)
+ testHandler.flush()
+ verify(broadcastHelper, times(2)).sendPackageBroadcast(
+ eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), bundleCaptor.capture(),
+ anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
+
+ bundleCaptor.allValues.forEachIndexed { i, it ->
+ var changedPackages = it.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ var changedUids = it.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
+ assertThat(changedPackages?.size).isEqualTo(1)
+ assertThat(changedUids?.size).isEqualTo(1)
+ assertThat(changedPackages?.get(0)).isEqualTo(packagesToChange[i])
+ assertThat(changedUids?.get(0)).isEqualTo(uidsToChange[i])
+ }
+ }
} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
index fbbb814388f7..4d13981947c4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
@@ -53,7 +53,6 @@ class PackageFreezerTest {
rule.system().dataAppDirectory)
}
var pms = PackageManagerService(rule.mocks().injector,
- false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /*isEngBuild*/,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
index bd012fc7837e..5f9ef584fa0f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
@@ -28,6 +28,7 @@ import com.android.server.testutils.whenever
import org.junit.Before
import org.junit.Rule
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
@@ -101,6 +102,7 @@ open class PackageHelperTestBase {
whenever(rule.mocks().userManagerService.hasUserRestriction(
eq(UserManager.DISALLOW_UNINSTALL_APPS), eq(TEST_USER_ID))).thenReturn(true)
mockKnownPackages(pms)
+ mockUnifiedSeparatedBroadcastList()
}
private fun mockKnownPackages(pms: PackageManagerService) {
@@ -128,7 +130,6 @@ open class PackageHelperTestBase {
rule.system().dataAppDirectory)
}
var pms = PackageManagerService(rule.mocks().injector,
- false /* coreOnly */,
false /* factoryTest */,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /* isEngBuild */,
@@ -138,4 +139,26 @@ open class PackageHelperTestBase {
rule.system().validateFinalState()
return pms
}
+
+ protected fun mockUnifiedSeparatedBroadcastList() {
+ whenever(broadcastHelper.getBroadcastParams(any(Computer::class.java),
+ any() as Array<String>, any(IntArray::class.java), anyInt()
+ )).thenReturn(ArrayList<BroadcastParams>().apply {
+ this.add(BroadcastParams(packagesToChange[0], uidsToChange[0], IntArray(0),
+ TEST_USER_ID).apply {
+ this.addPackage(packagesToChange[1], uidsToChange[1])
+ })
+ })
+ }
+
+ protected fun mockDividedSeparatedBroadcastList(allowlist1: IntArray?, allowlist2: IntArray?) {
+ whenever(broadcastHelper.getBroadcastParams(any(Computer::class.java),
+ any() as Array<String>, any(IntArray::class.java), anyInt()
+ )).thenReturn(ArrayList<BroadcastParams>().apply {
+ this.add(BroadcastParams(packagesToChange[0], uidsToChange[0],
+ allowlist1 ?: IntArray(0), TEST_USER_ID))
+ this.add(BroadcastParams(packagesToChange[1], uidsToChange[1],
+ allowlist2 ?: IntArray(0), TEST_USER_ID))
+ })
+ }
} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
index bbca121b7fdf..c9b36f0d974d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -57,7 +57,6 @@ class PackageManagerServiceBootTest {
private fun createPackageManagerService(): PackageManagerService {
return PackageManagerService(rule.mocks().injector,
- false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /*isEngBuild*/,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index 537a0280e24b..b9893f6ee170 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -165,7 +165,6 @@ class PackageManagerServiceHibernationTests {
private fun createPackageManagerService(): PackageManagerService {
return PackageManagerService(rule.mocks().injector,
- false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /*isEngBuild*/,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index bd36322664b5..b42a3b0719df 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -104,7 +104,6 @@ class SharedLibrariesImplTest {
stageScanExistingPackages()
mPms = spy(PackageManagerService(mMockSystem.mocks().injector,
- false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
false /*isEngBuild*/,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index b9d6b2ccd306..df53dfe288c6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -20,20 +20,14 @@ import android.content.Intent
import android.content.pm.SuspendDialogInfo
import android.os.Binder
import android.os.PersistableBundle
-import android.util.ArrayMap
-import android.util.SparseArray
-import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.snapshot.PackageDataSnapshot
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.nullable
-import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mockito.argThat
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -304,14 +298,11 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
@Test
@Throws(Exception::class)
fun sendPackagesSuspendedForUser_withSameVisibilityAllowList() {
- mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
- mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
-
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
- anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
+ anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
var changedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
var changedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
@@ -323,8 +314,8 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
@Test
@Throws(Exception::class)
fun sendPackagesSuspendedForUser_withDifferentVisibilityAllowList() {
- mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
- mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
+ mockDividedSeparatedBroadcastList(
+ intArrayOf(10001, 10002, 10003), intArrayOf(10001, 10002, 10007))
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
@@ -333,21 +324,20 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
nullable(), any(), nullable())
- bundleCaptor.allValues.forEach {
+ bundleCaptor.allValues.forEachIndexed { i, it ->
var changedPackages = it.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
var changedUids = it.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
assertThat(changedPackages?.size).isEqualTo(1)
assertThat(changedUids?.size).isEqualTo(1)
- assertThat(changedPackages?.get(0)).isAnyOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
- assertThat(changedUids?.get(0)).isAnyOf(packageSetting1.appId, packageSetting2.appId)
+ assertThat(changedPackages?.get(0)).isEqualTo(packagesToChange[i])
+ assertThat(changedUids?.get(0)).isEqualTo(uidsToChange[i])
}
}
@Test
@Throws(Exception::class)
fun sendPackagesSuspendedForUser_withNullVisibilityAllowList() {
- mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
- mockAllowList(packageSetting2, null)
+ mockDividedSeparatedBroadcastList(intArrayOf(10001, 10002, 10003), null)
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
@@ -356,13 +346,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
nullable(), nullable(), nullable())
- bundleCaptor.allValues.forEach {
+ bundleCaptor.allValues.forEachIndexed { i, it ->
var changedPackages = it.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
var changedUids = it.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
assertThat(changedPackages?.size).isEqualTo(1)
assertThat(changedUids?.size).isEqualTo(1)
- assertThat(changedPackages?.get(0)).isAnyOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
- assertThat(changedUids?.get(0)).isAnyOf(packageSetting1.appId, packageSetting2.appId)
+ assertThat(changedPackages?.get(0)).isEqualTo(packagesToChange[i])
+ assertThat(changedUids?.get(0)).isEqualTo(uidsToChange[i])
}
}
@@ -383,17 +373,4 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
assertThat(modifiedUids).asList().containsExactly(
packageSetting1.appId, packageSetting2.appId)
}
-
- private fun allowList(vararg uids: Int) = SparseArray<IntArray>().apply {
- this.put(TEST_USER_ID, uids)
- }
-
- private fun mockAllowList(pkgSetting: PackageStateInternal, list: SparseArray<IntArray>?) {
- whenever(rule.mocks().appsFilter.getVisibilityAllowList(
- any(PackageDataSnapshot::class.java),
- argThat { it?.packageName == pkgSetting.packageName }, any(IntArray::class.java),
- any() as ArrayMap<String, out PackageStateInternal>
- ))
- .thenReturn(list)
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index e9f0bd9db9fe..8890070c5821 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -19,8 +19,12 @@ package com.android.server.accessibility.magnification;
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import android.annotation.UiContext;
+import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -76,7 +80,8 @@ public class WindowMagnificationGestureHandlerTest {
private WindowMagnificationManager mWindowMagnificationManager;
private MockWindowMagnificationConnection mMockConnection;
- private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+ private SpyWindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+ private WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
@Mock
MagnificationGestureHandler.Callback mMockCallback;
@Mock
@@ -89,9 +94,11 @@ public class WindowMagnificationGestureHandlerTest {
mock(WindowMagnificationManager.Callback.class), mMockTrace,
new MagnificationScaleProvider(mContext));
mMockConnection = new MockWindowMagnificationConnection();
- mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
+ mWindowMagnificationGestureHandler = new SpyWindowMagnificationGestureHandler(
mContext, mWindowMagnificationManager, mMockTrace, mMockCallback,
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
+ mMockWindowMagnificationGestureHandler =
+ mWindowMagnificationGestureHandler.getMockGestureHandler();
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
}
@@ -154,6 +161,18 @@ public class WindowMagnificationGestureHandlerTest {
});
}
+ @Test
+ public void testTripleTapAndHold_logSessionDuration() {
+ // perform triple tap on spy gesture handler
+ goFromStateIdleTo(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+ // perform up event on spy gesture handler
+ returnToNormalFrom(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+ verify(mMockWindowMagnificationGestureHandler)
+ .logMagnificationTripleTapAndHoldSession(anyLong());
+ }
+
private void forEachState(IntConsumer action) {
for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
action.accept(state);
@@ -335,4 +354,31 @@ public class WindowMagnificationGestureHandlerTest {
private String stateDump() {
return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
}
+
+ private static class SpyWindowMagnificationGestureHandler
+ extends WindowMagnificationGestureHandler {
+
+ private final WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
+
+ SpyWindowMagnificationGestureHandler(@UiContext Context context,
+ WindowMagnificationManager windowMagnificationMgr,
+ AccessibilityTraceManager trace,
+ Callback callback,
+ boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
+ super(context, windowMagnificationMgr, trace, callback, detectTripleTap,
+ detectShortcutTrigger, displayId);
+ mMockWindowMagnificationGestureHandler = mock(WindowMagnificationGestureHandler.class);
+ }
+
+ WindowMagnificationGestureHandler getMockGestureHandler() {
+ return mMockWindowMagnificationGestureHandler;
+ }
+
+ @Override
+ void logMagnificationTripleTapAndHoldSession(long duration) {
+ super.logMagnificationTripleTapAndHoldSession(duration);
+ mMockWindowMagnificationGestureHandler
+ .logMagnificationTripleTapAndHoldSession(duration);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 978000aa89d3..25ad2be3772e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -23,10 +23,12 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
@@ -293,6 +295,17 @@ public class WindowMagnificationManagerTest {
}
@Test
+ public void logTrackingTypingFocus_processScroll_logDuration() {
+ WindowMagnificationManager spyWindowMagnificationManager = spy(mWindowMagnificationManager);
+ spyWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, 50f, 50f);
+ spyWindowMagnificationManager.onImeWindowVisibilityChanged(TEST_DISPLAY, /* shown */ true);
+
+ spyWindowMagnificationManager.processScroll(TEST_DISPLAY, 10f, 10f);
+
+ verify(spyWindowMagnificationManager).logTrackingTypingFocus(anyLong());
+ }
+
+ @Test
public void onRectangleOnScreenRequested_trackingDisabledByOnDrag_withoutMovingMagnifier()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index d5c5745d6680..f28ad79c8488 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -37,8 +37,8 @@ import android.accounts.AccountManagerInternal;
import android.accounts.CantAddAccountActivity;
import android.accounts.IAccountManagerResponse;
import android.app.AppOpsManager;
-import android.app.PropertyInvalidatedCache;
import android.app.INotificationManager;
+import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
@@ -253,6 +253,26 @@ public class AccountManagerServiceTest extends AndroidTestCase {
}
@SmallTest
+ public void testCheckAddAccountLongName() throws Exception {
+ unlockSystemUser();
+ String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaa";
+ Account a11 = new Account(longString, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+
+ mAms.addAccountExplicitly(
+ a11, /* password= */ "p11", /* extras= */ null, /* callerPackage= */ null);
+
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ Account[] accounts = mAms.getAccountsAsUser(null,
+ UserHandle.getCallingUserId(), mContext.getOpPackageName());
+ assertEquals(0, accounts.length);
+ }
+
+
+ @SmallTest
public void testPasswords() throws Exception {
unlockSystemUser();
Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
diff --git a/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java
new file mode 100644
index 000000000000..6bb494d3a92a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 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.ambientcontext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.app.ambientcontext.AmbientContextEvent;
+import android.app.ambientcontext.AmbientContextEventRequest;
+import android.content.Intent;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit test for {@link AmbientContextManagerService}.
+ * atest FrameworksServicesTests:AmbientContextManagerServiceTest
+ */
+public class AmbientContextManagerServiceTest {
+ public static final String SYSTEM_PACKAGE_NAME = "com.android.frameworks.servicestests";
+ private static final int USER_ID = UserHandle.USER_SYSTEM;
+
+ @SmallTest
+ @Test
+ public void testClientRequest() {
+ AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
+ .addEventType(AmbientContextEvent.EVENT_COUGH)
+ .build();
+ Intent intent = new Intent();
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ InstrumentationRegistry.getTargetContext(), 0,
+ intent, PendingIntent.FLAG_IMMUTABLE);
+ AmbientContextManagerService.ClientRequest clientRequest =
+ new AmbientContextManagerService.ClientRequest(USER_ID, request,
+ pendingIntent, new RemoteCallback(result -> {}));
+
+ assertThat(clientRequest.getRequest()).isEqualTo(request);
+ assertThat(clientRequest.getPackageName()).isEqualTo(SYSTEM_PACKAGE_NAME);
+ assertThat(clientRequest.hasUserId(USER_ID)).isTrue();
+ assertThat(clientRequest.hasUserId(-1)).isFalse();
+ assertThat(clientRequest.hasUserIdAndPackageName(USER_ID, SYSTEM_PACKAGE_NAME)).isTrue();
+ assertThat(clientRequest.hasUserIdAndPackageName(-1, SYSTEM_PACKAGE_NAME)).isFalse();
+ assertThat(clientRequest.hasUserIdAndPackageName(USER_ID, "random.package.name"))
+ .isFalse();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/ambientcontext/OWNERS b/services/tests/servicestests/src/com/android/server/ambientcontext/OWNERS
new file mode 100644
index 000000000000..ddfb6e39fd3a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ambientcontext/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/ambientcontext/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 7610b7ca5ec3..b33e22fe6d1e 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -164,7 +164,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
}
public void testRequestPinAppWidget() {
- ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
+ ComponentName provider = new ComponentName(mTestContext, TestAppWidgetProvider.class);
// Set up users.
when(mMockShortcutService.requestPinAppWidget(anyString(),
any(AppWidgetProviderInfo.class), eq(null), eq(null), anyInt()))
@@ -289,6 +289,16 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
assertEquals(4, updates.size());
}
+ public void testReceiveBroadcastBehavior_enableAndUpdate() {
+ TestAppWidgetProvider testAppWidgetProvider = new TestAppWidgetProvider();
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE);
+
+ testAppWidgetProvider.onReceive(mTestContext, intent);
+
+ assertTrue(testAppWidgetProvider.isBehaviorSuccess());
+ }
+
+
public void testUpdatesReceived_queueNotEmpty_multipleWidgetIdProvided() {
int widgetId = setupHostAndWidget();
int widgetId2 = bindNewWidget();
@@ -385,7 +395,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
}
private int bindNewWidget() {
- ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
+ ComponentName provider = new ComponentName(mTestContext, TestAppWidgetProvider.class);
int widgetId = mService.allocateAppWidgetId(mPkgName, HOST_ID);
assertTrue(mManager.bindAppWidgetIdIfAllowed(widgetId, provider));
assertEquals(provider, mManager.getAppWidgetInfo(widgetId).provider);
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/TestAppWidgetProvider.java b/services/tests/servicestests/src/com/android/server/appwidget/TestAppWidgetProvider.java
new file mode 100644
index 000000000000..6c11a6829c12
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appwidget/TestAppWidgetProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 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.appwidget;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+
+/**
+ * Placeholder widget for testing
+ */
+public class TestAppWidgetProvider extends AppWidgetProvider {
+ private boolean mEnabled;
+ private boolean mUpdated;
+
+ TestAppWidgetProvider() {
+ super();
+ mEnabled = false;
+ mUpdated = false;
+ }
+
+ public boolean isBehaviorSuccess() {
+ return mEnabled && mUpdated;
+ }
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+ int[] appWidgetids) {
+ mUpdated = true;
+ }
+
+ @Override
+ public void onEnabled(Context context) {
+ mEnabled = true;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java b/services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java
new file mode 100644
index 000000000000..049c745fc128
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/restore/FullRestoreEngineTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 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.backup.restore;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.backup.BackupAgent;
+import android.platform.test.annotations.Presubmit;
+import android.system.OsConstants;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.backup.FileMetadata;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class FullRestoreEngineTest {
+ private static final String DEFAULT_PACKAGE_NAME = "package";
+ private static final String DEFAULT_DOMAIN_NAME = "domain";
+ private static final String NEW_PACKAGE_NAME = "new_package";
+ private static final String NEW_DOMAIN_NAME = "new_domain";
+
+ private FullRestoreEngine mRestoreEngine;
+
+ @Before
+ public void setUp() {
+ mRestoreEngine = new FullRestoreEngine();
+ }
+
+ @Test
+ public void shouldSkipReadOnlyDir_skipsAllReadonlyDirsAndTheirChildren() {
+ // Create the file tree.
+ TestFile[] testFiles = new TestFile[] {
+ TestFile.dir("root"),
+ TestFile.file("root/auth_token"),
+ TestFile.dir("root/media"),
+ TestFile.file("root/media/picture1.png"),
+ TestFile.file("root/push_token.txt"),
+ TestFile.dir("root/read-only-dir-1").markReadOnly().expectSkipped(),
+ TestFile.dir("root/read-only-dir-1/writable-subdir").expectSkipped(),
+ TestFile.file("root/read-only-dir-1/writable-subdir/writable-file").expectSkipped(),
+ TestFile.dir("root/read-only-dir-1/writable-subdir/read-only-subdir-2")
+ .markReadOnly().expectSkipped(),
+ TestFile.file("root/read-only-dir-1/writable-file").expectSkipped(),
+ TestFile.file("root/random-stuff.txt"),
+ TestFile.dir("root/database"),
+ TestFile.file("root/database/users.db"),
+ TestFile.dir("root/read-only-dir-2").markReadOnly().expectSkipped(),
+ TestFile.file("root/read-only-dir-2/writable-file-1").expectSkipped(),
+ TestFile.file("root/read-only-dir-2/writable-file-2").expectSkipped(),
+ };
+
+ assertCorrectItemsAreSkipped(testFiles);
+ }
+
+ @Test
+ public void shouldSkipReadOnlyDir_onlySkipsChildrenUnderTheSamePackage() {
+ TestFile[] testFiles = new TestFile[]{
+ TestFile.dir("read-only-dir").markReadOnly().expectSkipped(),
+ TestFile.file("read-only-dir/file").expectSkipped(),
+ TestFile.file("read-only-dir/file-from-different-package")
+ .setPackage(NEW_PACKAGE_NAME),
+ };
+
+ assertCorrectItemsAreSkipped(testFiles);
+ }
+
+ @Test
+ public void shouldSkipReadOnlyDir_onlySkipsChildrenUnderTheSameDomain() {
+ TestFile[] testFiles = new TestFile[]{
+ TestFile.dir("read-only-dir").markReadOnly().expectSkipped(),
+ TestFile.file("read-only-dir/file").expectSkipped(),
+ TestFile.file("read-only-dir/file-from-different-domain")
+ .setDomain(NEW_DOMAIN_NAME),
+ };
+
+ assertCorrectItemsAreSkipped(testFiles);
+ }
+
+ private void assertCorrectItemsAreSkipped(TestFile[] testFiles) {
+ // Verify all directories marked with .expectSkipped are skipped.
+ for (TestFile testFile : testFiles) {
+ boolean actualExcluded = mRestoreEngine.shouldSkipReadOnlyDir(testFile.mMetadata);
+ boolean expectedExcluded = testFile.mShouldSkip;
+ assertWithMessage(testFile.mMetadata.path).that(actualExcluded).isEqualTo(
+ expectedExcluded);
+ }
+ }
+
+ private static class TestFile {
+ private final FileMetadata mMetadata;
+ private boolean mShouldSkip;
+
+ static TestFile dir(String path) {
+ return new TestFile(path, BackupAgent.TYPE_DIRECTORY);
+ }
+
+ static TestFile file(String path) {
+ return new TestFile(path, BackupAgent.TYPE_FILE);
+ }
+
+ TestFile markReadOnly() {
+ mMetadata.mode = 0;
+ return this;
+ }
+
+ TestFile expectSkipped() {
+ mShouldSkip = true;
+ return this;
+ }
+
+ TestFile setPackage(String packageName) {
+ mMetadata.packageName = packageName;
+ return this;
+ }
+
+ TestFile setDomain(String domain) {
+ mMetadata.domain = domain;
+ return this;
+ }
+
+ private TestFile(String path, int type) {
+ FileMetadata metadata = new FileMetadata();
+ metadata.path = path;
+ metadata.type = type;
+ metadata.packageName = DEFAULT_PACKAGE_NAME;
+ metadata.domain = DEFAULT_DOMAIN_NAME;
+ metadata.mode = OsConstants.S_IWUSR; // Mark as writable.
+ mMetadata = metadata;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 7aea65e78616..310c8f4b5d69 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -19,6 +19,7 @@ package com.android.server.backup.utils;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
@@ -250,9 +251,9 @@ public class BackupEligibilityRulesTest {
/* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
OperationType.ADB_BACKUP);
- when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
- eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
- /* allowAdbBackup */ false));
+ when(mPackageManager.getPropertyAsUser(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
+ eq(TEST_PACKAGE_NAME), isNull(), eq(mUserId)))
+ .thenReturn(getAdbBackupProperty(/* allowAdbBackup */ false));
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
@@ -267,9 +268,9 @@ public class BackupEligibilityRulesTest {
/* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
OperationType.ADB_BACKUP);
- when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
- eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
- /* allowAdbBackup */ true));
+ when(mPackageManager.getPropertyAsUser(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
+ eq(TEST_PACKAGE_NAME), isNull(), eq(mUserId)))
+ .thenReturn(getAdbBackupProperty(/* allowAdbBackup */ true));
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index f40b31a0bc0d..abf992b6c637 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -415,7 +415,7 @@ public class CoexCoordinatorTest {
// Auth was attempted
when(mUdfpsClient.getState())
.thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED);
- verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).sendHapticFeedback();
verify(mCallback).handleLifecycleAfterAuth();
// Then face rejected. Note that scheduler leaves UDFPS in the CoexCoordinator since
@@ -425,7 +425,7 @@ public class CoexCoordinatorTest {
LockoutTracker.LOCKOUT_NONE, faceCallback);
verify(faceCallback).sendHapticFeedback();
verify(faceCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
- verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).sendHapticFeedback();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
new file mode 100644
index 000000000000..ca3677e3b5ff
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.common.SensorStrength;
+import android.hardware.biometrics.fingerprint.FingerprintSensorType;
+import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.SensorLocation;
+import android.hardware.biometrics.fingerprint.SensorProps;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
+import com.android.server.biometrics.log.BiometricContext;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+@Presubmit
+@SmallTest
+public class FingerprintServiceTest {
+
+ private static final int ID_DEFAULT = 2;
+ private static final int ID_VIRTUAL = 6;
+ private static final String NAME_DEFAULT = "default";
+ private static final String NAME_VIRTUAL = "virtual";
+
+ @Rule
+ public final MockitoRule mMockito = MockitoJUnit.rule();
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public final FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
+
+ @Mock
+ private BiometricContext mBiometricContext;
+ @Mock
+ private IBiometricService mIBiometricService;
+ @Mock
+ private IFingerprint mIFingerprintDefault;
+ @Mock
+ private IFingerprint mIFingerprintVirtual;
+
+ private final SensorProps mSensorPropsDefault = createProps(ID_DEFAULT,
+ SensorStrength.STRONG, FingerprintSensorType.POWER_BUTTON);
+ private final SensorProps mSensorPropsVirtual = createProps(ID_VIRTUAL,
+ SensorStrength.STRONG, FingerprintSensorType.UNDER_DISPLAY_OPTICAL);
+ private FingerprintService mService;
+
+ @Before
+ public void setup() throws Exception {
+ when(mIFingerprintDefault.getSensorProps()).thenReturn(
+ new SensorProps[]{mSensorPropsDefault});
+ when(mIFingerprintVirtual.getSensorProps()).thenReturn(
+ new SensorProps[]{mSensorPropsVirtual});
+
+ mContext.getTestablePermissions().setPermission(
+ USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
+
+ mService = new FingerprintService(mContext, mBiometricContext,
+ () -> mIBiometricService,
+ (fqName) -> {
+ if (fqName.endsWith(NAME_DEFAULT)) return mIFingerprintDefault;
+ if (fqName.endsWith(NAME_VIRTUAL)) return mIFingerprintVirtual;
+ return null;
+ });
+ }
+
+ @Test
+ public void registerAuthenticators_defaultOnly() throws RemoteException {
+ mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
+
+ verify(mIBiometricService).registerAuthenticator(eq(ID_DEFAULT), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void registerAuthenticators_virtualOnly() throws RemoteException {
+ Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext),
+ Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 1);
+
+ mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
+
+ verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void registerAuthenticators_virtualAlwaysWhenNoOther() throws RemoteException {
+ mService.registerAuthenticatorsForService(List.of(NAME_VIRTUAL), List.of());
+
+ verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
+ }
+
+ private static SensorProps createProps(int id, byte strength, byte type) {
+ final SensorProps props = new SensorProps();
+ props.commonProps = new CommonProps();
+ props.commonProps.sensorId = id;
+ props.commonProps.sensorStrength = strength;
+ props.sensorType = type;
+ props.sensorLocations = new SensorLocation[]{new SensorLocation()};
+ return props;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClientTest.java
new file mode 100644
index 000000000000..282c782e752a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClientTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 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.aidl;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.fingerprint.Fingerprint;
+import android.platform.test.annotations.Presubmit;
+import android.testing.TestableContext;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Presubmit
+@SmallTest
+public class FingerprintInternalCleanupClientTest {
+
+ private static final int SENSOR_ID = 22;
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+
+ @Mock
+ private AidlSession mAidlSession;
+ @Mock
+ private ISession mSession;
+ @Mock
+ private BiometricLogger mLogger;
+ @Mock
+ private BiometricContext mBiometricContext;
+ @Mock
+ private FingerprintUtils mFingerprintUtils;
+ @Mock
+ private ClientMonitorCallback mCallback;
+
+ private FingerprintInternalCleanupClient mClient;
+ private List<Integer> mAddedIds;
+
+ @Before
+ public void setup() {
+ when(mAidlSession.getSession()).thenReturn(mSession);
+ mAddedIds = new ArrayList<>();
+ }
+
+ @Ignore("TODO(b/229015801): verify cleanup behavior")
+ @Test
+ public void removesUnknownTemplate() throws Exception {
+ mClient = createClient();
+
+ final List<Fingerprint> templates = List.of(
+ new Fingerprint("one", 1, 1),
+ new Fingerprint("two", 2, 1)
+ );
+ mClient.start(mCallback);
+ for (int i = templates.size() - 1; i >= 0; i--) {
+ mClient.getCurrentEnumerateClient().onEnumerationResult(templates.get(i), i);
+ }
+ for (int i = templates.size() - 1; i >= 0; i--) {
+ mClient.getCurrentRemoveClient().onRemoved(templates.get(i), 0);
+ }
+
+ assertThat(mAddedIds).isEmpty();
+ final ArgumentCaptor<int[]> captor = ArgumentCaptor.forClass(int[].class);
+ verify(mSession, times(2)).removeEnrollments(captor.capture());
+ assertThat(captor.getAllValues().stream()
+ .flatMap(x -> Arrays.stream(x).boxed())
+ .collect(Collectors.toList()))
+ .containsExactly(1, 2);
+ verify(mCallback).onClientFinished(eq(mClient), eq(true));
+ }
+
+ @Test
+ public void addsUnknownTemplateWhenVirtualIsEnabled() throws Exception {
+ mClient = createClient();
+ mClient.setFavorHalEnrollments();
+
+ final List<Fingerprint> templates = List.of(
+ new Fingerprint("one", 1, 1),
+ new Fingerprint("two", 2, 1)
+ );
+ mClient.start(mCallback);
+ for (int i = templates.size() - 1; i >= 0; i--) {
+ mClient.getCurrentEnumerateClient().onEnumerationResult(templates.get(i), i);
+ }
+
+ assertThat(mAddedIds).containsExactly(1, 2);
+ verify(mSession, never()).removeEnrollments(any());
+ verify(mCallback).onClientFinished(eq(mClient), eq(true));
+ }
+
+ protected FingerprintInternalCleanupClient createClient() {
+ final List<Fingerprint> enrollments = new ArrayList<>();
+ final Map<Integer, Long> authenticatorIds = new HashMap<>();
+ return new FingerprintInternalCleanupClient(mContext, () -> mAidlSession, 2 /* userId */,
+ "the.test.owner", SENSOR_ID, mLogger, mBiometricContext, enrollments,
+ mFingerprintUtils, authenticatorIds) {
+ @Override
+ protected void onAddUnknownTemplate(int userId,
+ @NonNull BiometricAuthenticator.Identifier identifier) {
+ mAddedIds.add(identifier.getBiometricId());
+ }
+ };
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
index aa2d97e38928..5a6d2d398f7d 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
@@ -83,10 +83,8 @@ class InputManagerMockHelper {
// We only use a subset of the fields of InputDevice in InputController.
final InputDevice device = new InputDevice(mDevices.size() /*id*/, 1 /*generation*/, 0,
inv.getArgument(0) /*name*/, inv.getArgument(1) /*vendorId*/,
- inv.getArgument(2) /*productId*/, inv.getArgument(3) /*descriptor*/,
- true /*isExternal*/, 0 /*sources*/, 0 /*keyboardType*/,
- null /*keyCharacterMap*/, false /*hasVibrator*/, false /*hasMic*/,
- false /*hasButtonUnderPad*/, false /*hasSensor*/, false /*hasBattery*/);
+ inv.getArgument(2) /*productId*/, inv.getArgument(3) /*descriptor*/, true, 0, 0,
+ null, false, false, false, false, false);
mDevices.add(device);
try {
mDevicesChangedListener.onInputDevicesChanged(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 412722d68f43..72fac55d7c99 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -69,15 +69,9 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
private ComponentName mFakeAdmin;
private class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider {
- boolean mIsFileBasedEncryptionEnabled;
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
int[] mUsers;
- @Override
- public boolean storageManagerIsFileBasedEncryptionEnabled() {
- return mIsFileBasedEncryptionEnabled;
- }
-
private JournaledFile makeJournaledFile(int userId, String fileName) {
File parentDir = getServices().environment.getUserSystemDirectory(userId);
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index fe3034dc569d..ce7b367ec7ec 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -243,6 +243,7 @@ public final class DeviceStateManagerServiceTest {
assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
}
+ @FlakyTest(bugId = 223153452)
@Test
public void registerCallback() throws RemoteException {
TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 356600d84099..0a5df410bcdb 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -1091,6 +1091,12 @@ public class BrightnessTrackerTest {
}
@Override
+ public AtomicFile getLegacyFile(String filename) {
+ // Don't have the test write / read from anywhere.
+ return null;
+ }
+
+ @Override
public long currentTimeMillis() {
return mCurrentTimeMillis;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1e97c1c5c5bc..c11e2b02cd97 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -203,7 +203,7 @@ public class DisplayManagerServiceTest {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
- displayManager.systemReady(false /* safeMode */, true /* onlyCore */);
+ displayManager.systemReady(false /* safeMode */);
displayManager.windowManagerAndInputReady();
// This is effectively the DisplayManager service published to ServiceManager.
@@ -279,7 +279,7 @@ public class DisplayManagerServiceTest {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
- displayManager.systemReady(false /* safeMode */, true /* onlyCore */);
+ displayManager.systemReady(false /* safeMode */);
displayManager.windowManagerAndInputReady();
// This is effectively the DisplayManager service published to ServiceManager.
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 484b5a8dae1a..0f6addb452a1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -982,7 +982,11 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
- public void handleOnInitializeCecComplete_ByScreenOn() {
+ public void handleOnInitializeCecComplete_ByScreenOn_PowerControlModeTv() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.POWER_CONTROL_MODE_TV);
+
mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
mHdmiControlService.INITIATED_BY_SCREEN_ON);
mTestLooper.dispatchAll();
@@ -999,6 +1003,27 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void handleOnInitializeCecComplete_ByScreenOn_PowerControlModeNone() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.POWER_CONTROL_MODE_NONE);
+
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
public void handleOnInitializeCecComplete_ByWakeUpMessage() {
mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
mHdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE);
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 928c76d07d7c..f1383119605e 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -493,15 +493,16 @@ public class JobStoreTest {
* Helper function to kick a {@link JobInfo} through a persistence cycle and
* assert that it's unchanged.
*/
- private void assertPersistedEquals(JobInfo first) throws Exception {
+ private void assertPersistedEquals(JobInfo firstInfo) throws Exception {
mTaskStoreUnderTest.clear();
- mTaskStoreUnderTest.add(JobStatus.createFromJobInfo(first, SOME_UID, null, -1, null));
+ JobStatus first = JobStatus.createFromJobInfo(firstInfo, SOME_UID, null, -1, null);
+ mTaskStoreUnderTest.add(first);
waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
final JobStatus second = jobStatusSet.getAllJobs().iterator().next();
- assertTasksEqual(first, second.getJob());
+ assertTasksEqual(first.getJob(), second.getJob());
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index ab292ab5381e..20482afd53ac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -30,7 +30,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
@@ -90,16 +89,17 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
- final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ final PackageInfo activePkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE);
assertThat(activePkgPi).isNotNull();
assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG);
- final PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+ final PackageInfo factoryPkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE);
assertThat(factoryPkgPi).isNull();
@@ -107,16 +107,17 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
- PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ PackageInfo factoryPkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE);
assertThat(factoryPkgPi).isNotNull();
assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG);
- final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+ final PackageInfo activePkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE);
assertThat(activePkgPi).isNull();
@@ -124,23 +125,26 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsNone() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
+ assertThat(apexPackageInfo.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
}
@Test
public void testGetApexSystemServices() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(new ApexInfo[] {
+ ApexInfo[] apexInfo = new ApexInfo[] {
createApexInfoForTestPkg(false, true, 1),
// only active apex reports apex-system-service
createApexInfoForTestPkg(true, false, 2),
- });
+ };
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ mApexManager.notifyScanResult(scanResults);
List<ApexSystemServiceInfo> services = mApexManager.getApexSystemServices();
assertThat(services).hasSize(1);
@@ -150,65 +154,72 @@ public class ApexManagerTest {
@Test
public void testGetActivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getActivePackages()).isNotEmpty();
+ assertThat(apexPackageInfo.getActivePackages()).isNotEmpty();
}
@Test
public void testGetActivePackages_noneActivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getActivePackages()).isEmpty();
+ assertThat(apexPackageInfo.getActivePackages()).isEmpty();
}
@Test
public void testGetFactoryPackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo [] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
+ assertThat(apexPackageInfo.getFactoryPackages()).isNotEmpty();
}
@Test
public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getFactoryPackages()).isEmpty();
+ assertThat(apexPackageInfo.getFactoryPackages()).isEmpty();
}
@Test
public void testGetInactivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getInactivePackages()).isNotEmpty();
+ assertThat(apexPackageInfo.getInactivePackages()).isNotEmpty();
}
@Test
public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.getInactivePackages()).isEmpty();
+ assertThat(apexPackageInfo.getInactivePackages()).isEmpty();
}
@Test
public void testIsApexPackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
+ assertThat(apexPackageInfo.isApexPackage(TEST_APEX_PKG)).isTrue();
}
@Test
@@ -318,9 +329,11 @@ public class ApexManagerTest {
final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getApkInApexInstallError(activeApex.apexModuleName)).isNull();
mApexManager.reportErrorWithApkInApex(activeApex.apexDirectory.getAbsolutePath(),
@@ -345,9 +358,11 @@ public class ApexManagerTest {
when(fakeApkInApex.getBaseApkPath()).thenReturn("/apex/" + TEST_APEX_PKG + "randomSuffix");
when(fakeApkInApex.getPackageName()).thenReturn("randomPackageName");
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty();
mApexManager.registerApkInApex(fakeApkInApex);
@@ -355,25 +370,14 @@ public class ApexManagerTest {
}
@Test
- public void testInstallPackageFailsToInstallNewApex() throws Exception {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
-
- File apex = extractResource("test.apex_rebootless_v1", "test.rebootless_apex_v1.apex");
- PackageManagerException e = expectThrows(PackageManagerException.class,
- () -> mApexManager.installPackage(apex, mPackageParser2));
- assertThat(e).hasMessageThat().contains("It is forbidden to install new APEX packages");
- }
-
- @Test
public void testInstallPackage_activeOnSystem() throws Exception {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
/* isFactory= */ true, extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex"));
- when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = new ApexInfo[]{activeApexInfo};
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
@@ -381,23 +385,26 @@ public class ApexManagerTest {
when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
- mApexManager.installPackage(installedApex, mPackageParser2);
+ newApexInfo = mApexManager.installPackage(installedApex);
+ apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ PackageInfo newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_ACTIVE_PACKAGE);
assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
+ .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
.isEqualTo(ApplicationInfo.FLAG_INSTALLED);
- PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ PackageInfo factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_FACTORY_PACKAGE);
assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(activeApexInfo.modulePath);
assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
.isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
}
@Test
@@ -408,10 +415,10 @@ public class ApexManagerTest {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
/* isFactory= */ false, extractResource("test.apex.rebootless@1",
"test.rebootless_apex_v1.apex"));
- when(mApexService.getAllPackages())
- .thenReturn(new ApexInfo[]{factoryApexInfo, activeApexInfo});
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = new ApexInfo[]{factoryApexInfo, activeApexInfo};
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
@@ -419,23 +426,26 @@ public class ApexManagerTest {
when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
- mApexManager.installPackage(installedApex, mPackageParser2);
+ newApexInfo = mApexManager.installPackage(installedApex);
+ apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ PackageInfo newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_ACTIVE_PACKAGE);
assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
+ .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
.isEqualTo(ApplicationInfo.FLAG_INSTALLED);
- PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ PackageInfo factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_FACTORY_PACKAGE);
assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(factoryApexInfo.modulePath);
assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
.isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
}
@Test
@@ -443,9 +453,10 @@ public class ApexManagerTest {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
/* isFactory= */ false, extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex"));
- when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexInfo[] apexInfo = new ApexInfo[]{activeApexInfo};
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
when(mApexService.installAndActivatePackage(anyString())).thenThrow(
new RuntimeException("install failed :("));
@@ -453,41 +464,7 @@ public class ApexManagerTest {
File installedApex = extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex");
assertThrows(PackageManagerException.class,
- () -> mApexManager.installPackage(installedApex, mPackageParser2));
- }
-
- @Test
- public void testInstallPackageSignedWithWrongCertificate() throws Exception {
- File activeApex = extractResource("shim_v1", "com.android.apex.cts.shim.apex");
- ApexInfo activeApexInfo = createApexInfo("com.android.apex.cts.shim", 1,
- /* isActive= */ true, /* isFactory= */ false, activeApex);
- when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
-
- File installedApex = extractResource("shim_different_certificate",
- "com.android.apex.cts.shim.v2_different_certificate.apex");
- PackageManagerException e = expectThrows(PackageManagerException.class,
- () -> mApexManager.installPackage(installedApex, mPackageParser2));
- assertThat(e).hasMessageThat().contains("APK container signature of ");
- assertThat(e).hasMessageThat().contains(
- "is not compatible with currently installed on device");
- }
-
- @Test
- public void testInstallPackageUnsignedApexContainer() throws Exception {
- File activeApex = extractResource("shim_v1", "com.android.apex.cts.shim.apex");
- ApexInfo activeApexInfo = createApexInfo("com.android.apex.cts.shim", 1,
- /* isActive= */ true, /* isFactory= */ false, activeApex);
- when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
-
- File installedApex = extractResource("shim_unsigned_apk_container",
- "com.android.apex.cts.shim.v2_unsigned_apk_container.apex");
- PackageManagerException e = expectThrows(PackageManagerException.class,
- () -> mApexManager.installPackage(installedApex, mPackageParser2));
- assertThat(e).hasMessageThat().contains("Failed to collect certificates from ");
+ () -> mApexManager.installPackage(installedApex));
}
@Test
@@ -496,9 +473,10 @@ public class ApexManagerTest {
ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
apexInfo[0].moduleName = moduleName;
- when(mApexService.getAllPackages()).thenReturn(apexInfo);
- mApexManager.scanApexPackagesTraced(mPackageParser2,
- ParallelPackageParser.makeExecutorService());
+ ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
+ List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
+ apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getActivePackageNameForApexModuleName(moduleName))
.isEqualTo(TEST_APEX_PKG);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 2fd7853971fe..0841bfc1d88c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -638,7 +638,7 @@ public class PackageParserTest {
public static class CachePackageNameParser extends PackageParser2 {
CachePackageNameParser(@Nullable File cacheDir) {
- super(null, false, null, null, new Callback() {
+ super(null, null, null, new Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
return true;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
index c489cf0a138d..fc86b92c9a1f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
@@ -17,6 +17,8 @@
package com.android.server.pm;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.verify;
@@ -82,7 +84,7 @@ public class UserDataPreparerTest {
FileUtils.deleteContents(ctx.getCacheDir());
mInstallLock = new Object();
MockitoAnnotations.initMocks(this);
- mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock, false,
+ mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock,
ctx.getCacheDir());
when(mContextMock.getSystemServiceName(StorageManager.class))
.thenReturn(Context.STORAGE_SERVICE);
@@ -129,22 +131,16 @@ public class UserDataPreparerTest {
}
@Test
- public void testDestroyUserData() throws Exception {
- // Add file in CE
+ public void testDestroyUserData_De_DoesNotDestroyCe() throws Exception {
+ // Add file in CE storage
File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
systemCeDir.mkdirs();
File ceFile = new File(systemCeDir, "file");
writeFile(ceFile, "-----" );
- testDestroyUserData_De();
- // CE directory should be preserved
+ // Destroy DE storage, then verify that CE storage wasn't destroyed too.
+ mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty(
systemCeDir)));
-
- testDestroyUserData_Ce();
-
- // Verify that testDir is empty
- assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
- mUserDataPreparer.testDir)));
}
@Test
@@ -163,7 +159,13 @@ public class UserDataPreparerTest {
verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_DE));
- assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir)));
+ // systemDir (normal path: /data/system/users/$userId) should have been deleted.
+ assertFalse(systemDir.exists());
+ // systemDeDir (normal path: /data/system_de/$userId) should still exist but be empty, since
+ // UserDataPreparer itself is responsible for deleting the contents of this directory, but
+ // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
+ // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
+ assertTrue(systemDeDir.exists());
assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
systemDeDir)));
}
@@ -181,6 +183,11 @@ public class UserDataPreparerTest {
verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
+ // systemCeDir (normal path: /data/system_ce/$userId) should still exist but be empty, since
+ // UserDataPreparer itself is responsible for deleting the contents of this directory, but
+ // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
+ // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
+ assertTrue(systemCeDir.exists());
assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
systemCeDir)));
}
@@ -215,8 +222,8 @@ public class UserDataPreparerTest {
File testDir;
TestUserDataPreparer(Installer installer, Object installLock, Context context,
- boolean onlyCore, File testDir) {
- super(installer, installLock, context, onlyCore);
+ File testDir) {
+ super(installer, installLock, context);
this.testDir = testDir;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 07cca0ca6ba0..4d1c58d2c274 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -610,7 +610,7 @@ public class PackageParserLegacyCoreTest {
assertNotNull(pi.signingInfo);
assertTrue(pi.signingInfo.getApkContentsSigners().length > 0);
assertTrue(pi.isApex);
- assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0);
+ assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
index 7ca7682f1c82..6ee91b89cadc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.parsing
import android.content.pm.ApplicationInfo
-class TestPackageParser2 : PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
- null /* displayMetrics */, null /* cacheDir */, object : PackageParser2.Callback() {
+class TestPackageParser2 : PackageParser2(null /* separateProcesses */, null /* displayMetrics */,
+ null /* cacheDir */, object : PackageParser2.Callback() {
override fun isChangeEnabled(changeId: Long, appInfo: ApplicationInfo): Boolean {
return true
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 9ff7d69e09a6..40ce956a0790 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -943,27 +943,6 @@ public class PowerManagerServiceTest {
}
@Test
- public void testInattentiveSleep_dreamEnds_goesToSleepAfterTimeout() {
- setMinimumScreenOffTimeoutConfig(5);
- setAttentiveTimeout(30000);
- createService();
- startSystem();
-
- advanceTime(10000);
- forceDream();
- advanceTime(10000);
- final String pkg = mContextSpy.getOpPackageName();
- mService.getBinderServiceInstance().wakeUp(mClock.now(),
- PowerManager.WAKE_REASON_DREAM_FINISHED, "PowerManagerServiceTest:DREAM_FINISHED",
- pkg);
- advanceTime(10001);
-
- assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
- assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
- PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
- }
-
- @Test
public void testInattentiveSleep_goesToSleepWithWakeLock() {
final String pkg = mContextSpy.getOpPackageName();
final Binder token = new Binder();
@@ -986,6 +965,27 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testInattentiveSleep_dreamEnds_goesToSleepAfterTimeout() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(30000);
+ createService();
+ startSystem();
+
+ advanceTime(10000);
+ forceDream();
+ advanceTime(10000);
+ final String pkg = mContextSpy.getOpPackageName();
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_DREAM_FINISHED, "PowerManagerServiceTest:DREAM_FINISHED",
+ pkg);
+ advanceTime(10001);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
public void testInattentiveSleep_wakeLockOnAfterRelease_inattentiveSleepTimeoutNotAffected() {
final DisplayInfo info = new DisplayInfo();
info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 758a56f3d2ad..e9171c0c3514 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -393,14 +393,14 @@ public class SystemConfigTest {
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"A\"\n"
+ + " on-bootclasspath-before=\"Q\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("A");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
index d4222e6e0b63..c3d40daef412 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
@@ -16,41 +16,188 @@
package com.android.server.timedetector;
-import static com.google.common.truth.Truth.assertThat;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import android.app.time.Capabilities;
import android.app.time.TimeCapabilities;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
-import android.os.UserHandle;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Instant;
+
@RunWith(AndroidJUnit4.class)
public class ConfigurationInternalTest {
+ private static final int ARBITRARY_USER_ID = 99999;
+ private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
+ private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0);
+ private static final @Origin int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
+
+ /**
+ * Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
+ * {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
+ */
@Test
- public void capabilitiesAndConfig() {
- int userId = 112233;
- ConfigurationInternal configurationInternal = new ConfigurationInternal.Builder(userId)
- .setAutoDetectionEnabled(true)
+ public void test_unrestricted() {
+ ConfigurationInternal
+ baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+ .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(true)
.build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
- TimeCapabilities timeCapabilities = new TimeCapabilities.Builder(UserHandle.of(userId))
- .setConfigureAutoTimeDetectionEnabledCapability(Capabilities.CAPABILITY_POSSESSED)
- .setSuggestTimeManuallyCapability(Capabilities.CAPABILITY_POSSESSED)
- .build();
- TimeConfiguration timeConfiguration = new TimeConfiguration.Builder()
- .setAutoDetectionEnabled(true)
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
+
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
+
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ }
+ }
+
+ /** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
+ @Test
+ public void test_restricted() {
+ ConfigurationInternal
+ baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
+ .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+ .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(true)
.build();
- TimeCapabilitiesAndConfig expected =
- new TimeCapabilitiesAndConfig(timeCapabilities, timeConfiguration);
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
- assertThat(configurationInternal.capabilitiesAndConfig()).isEqualTo(expected);
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
+
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ }
}
+ /** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
+ @Test
+ public void test_autoDetectNotSupported() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(false)
+ .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+ .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
+
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ }
+ {
+ ConfigurationInternal
+ autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabledSetting(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
+
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeCapability());
+
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
new file mode 100644
index 000000000000..77b319b56acb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
@@ -0,0 +1,99 @@
+/*
+ * 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.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.time.TimeCapabilities;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
+
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** A partially implemented, fake implementation of ServiceConfigAccessor for tests. */
+class FakeServiceConfigAccessor implements ServiceConfigAccessor {
+
+ private final List<ConfigurationChangeListener> mConfigurationInternalChangeListeners =
+ new ArrayList<>();
+ private ConfigurationInternal mConfigurationInternal;
+
+ @Override
+ public void addConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+ mConfigurationInternalChangeListeners.add(listener);
+ }
+
+ @Override
+ public void removeConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+ mConfigurationInternalChangeListeners.remove(listener);
+ }
+
+ @Override
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mConfigurationInternal;
+ }
+
+ @Override
+ public boolean updateConfiguration(
+ @UserIdInt int userID, @NonNull TimeConfiguration requestedChanges) {
+ assertNotNull(mConfigurationInternal);
+ assertNotNull(requestedChanges);
+
+ // Simulate the real strategy's behavior: the new configuration will be updated to be the
+ // old configuration merged with the new if the user has the capability to up the settings.
+ // Then, if the configuration changed, the change listener is invoked.
+ TimeCapabilitiesAndConfig capabilitiesAndConfig =
+ mConfigurationInternal.capabilitiesAndConfig();
+ TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ TimeConfiguration newConfiguration =
+ capabilities.tryApplyConfigChanges(configuration, requestedChanges);
+ if (newConfiguration == null) {
+ return false;
+ }
+
+ if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
+ mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+
+ // Note: Unlike the real strategy, the listeners are invoked synchronously.
+ simulateConfigurationChangeForTests();
+ }
+ return true;
+ }
+
+ void initializeConfiguration(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal = configurationInternal;
+ }
+
+ void simulateConfigurationChangeForTests() {
+ for (ConfigurationChangeListener listener : mConfigurationInternalChangeListeners) {
+ listener.onChange();
+ }
+ }
+
+ @Override
+ public ConfigurationInternal getConfigurationInternal(int userId) {
+ assertEquals("Multi-user testing not supported currently",
+ userId, mConfigurationInternal.getUserId());
+ return mConfigurationInternal;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 4519890e72a1..e9617e9d973a 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -16,19 +16,27 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
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.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.ITimeDetectorListener;
+import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
@@ -36,11 +44,13 @@ import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.timezonedetector.TestCallerIdentityInjector;
import com.android.server.timezonedetector.TestHandler;
import org.junit.After;
@@ -50,16 +60,24 @@ import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.time.Instant;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorServiceTest {
+ private static final int ARBITRARY_USER_ID = 9999;
+ private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
+ private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0);
+ private static final int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
+
private Context mMockContext;
- private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
private TimeDetectorService mTimeDetectorService;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
+ private TestCallerIdentityInjector mTestCallerIdentityInjector;
+ private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
+ private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
@Before
@@ -71,10 +89,15 @@ public class TimeDetectorServiceTest {
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
+ mTestCallerIdentityInjector = new TestCallerIdentityInjector();
+ mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
+
mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
+ mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
mTimeDetectorService = new TimeDetectorService(
- mMockContext, mTestHandler, mStubbedTimeDetectorStrategy);
+ mMockContext, mTestHandler, mFakeServiceConfigAccessor,
+ mStubbedTimeDetectorStrategy, mTestCallerIdentityInjector);
}
@After
@@ -84,6 +107,146 @@ public class TimeDetectorServiceTest {
}
@Test(expected = SecurityException.class)
+ public void testGetCapabilitiesAndConfig_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ try {
+ mTimeDetectorService.getCapabilitiesAndConfig();
+ fail("Expected SecurityException");
+ } finally {
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ }
+ }
+
+ @Test
+ public void testGetCapabilitiesAndConfig() {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ConfigurationInternal configuration =
+ createConfigurationInternal(true /* autoDetectionEnabled*/);
+ mFakeServiceConfigAccessor.initializeConfiguration(configuration);
+
+ assertEquals(configuration.capabilitiesAndConfig(),
+ mTimeDetectorService.getCapabilitiesAndConfig());
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testAddListener_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ITimeDetectorListener mockListener = mock(ITimeDetectorListener.class);
+ try {
+ mTimeDetectorService.addListener(mockListener);
+ fail("Expected SecurityException");
+ } finally {
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ }
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testRemoveListener_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ITimeDetectorListener mockListener = mock(ITimeDetectorListener.class);
+ try {
+ mTimeDetectorService.removeListener(mockListener);
+ fail("Expected a SecurityException");
+ } finally {
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ }
+ }
+
+ @Test
+ public void testListenerRegistrationAndCallbacks() throws Exception {
+ ConfigurationInternal initialConfiguration =
+ createConfigurationInternal(false /* autoDetectionEnabled */);
+ mFakeServiceConfigAccessor.initializeConfiguration(initialConfiguration);
+
+ IBinder mockListenerBinder = mock(IBinder.class);
+ ITimeDetectorListener mockListener = mock(ITimeDetectorListener.class);
+
+ {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+ when(mockListener.asBinder()).thenReturn(mockListenerBinder);
+
+ mTimeDetectorService.addListener(mockListener);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ verify(mockListener).asBinder();
+ verify(mockListenerBinder).linkToDeath(any(), anyInt());
+ verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
+ reset(mockListenerBinder, mockListener, mMockContext);
+ }
+
+ {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ // Simulate the configuration being changed and verify the mockListener was notified.
+ TimeConfiguration autoDetectEnabledConfiguration =
+ createTimeConfiguration(true /* autoDetectionEnabled */);
+ mTimeDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
+
+ // The configuration update notification is asynchronous.
+ mTestHandler.waitForMessagesToBeProcessed();
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ verify(mockListener).onChange();
+ verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
+ reset(mockListenerBinder, mockListener, mMockContext);
+ }
+
+ {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+ when(mockListener.asBinder()).thenReturn(mockListenerBinder);
+ when(mockListenerBinder.unlinkToDeath(any(), anyInt())).thenReturn(true);
+
+ // Now remove the listener, change the config again, and verify the listener is not
+ // called.
+ mTimeDetectorService.removeListener(mockListener);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ verify(mockListener).asBinder();
+ verify(mockListenerBinder).unlinkToDeath(any(), eq(0));
+ verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
+ reset(mockListenerBinder, mockListener, mMockContext);
+ }
+
+ {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ TimeConfiguration autoDetectDisabledConfiguration =
+ createTimeConfiguration(false /* autoDetectionEnabled */);
+ mTimeDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
+ anyString());
+ verify(mockListener, never()).onChange();
+ verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
+ reset(mockListenerBinder, mockListener, mMockContext);
+ }
+ }
+
+ @Test(expected = SecurityException.class)
public void testSuggestTelephonyTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
@@ -248,6 +411,24 @@ public class TimeDetectorServiceTest {
mStubbedTimeDetectorStrategy.verifyDumpCalled();
}
+ private static TimeConfiguration createTimeConfiguration(boolean autoDetectionEnabled) {
+ return new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(autoDetectionEnabled)
+ .build();
+ }
+
+ private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
+ return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+ .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(autoDetectionEnabled)
+ .build();
+ }
+
private static TelephonyTimeSuggestion createTelephonyTimeSuggestion() {
int slotIndex = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
@@ -291,7 +472,7 @@ public class TimeDetectorServiceTest {
}
@Override
- public boolean suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+ public boolean suggestManualTime(int userId, ManualTimeSuggestion timeSuggestion) {
mLastManualSuggestion = timeSuggestion;
return true;
}
@@ -312,11 +493,6 @@ public class TimeDetectorServiceTest {
}
@Override
- public ConfigurationInternal getConfigurationInternal(int userId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 2d9903f9cf60..15a8996aef4c 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
@@ -52,6 +53,8 @@ import java.util.Objects;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorStrategyImplTest {
+ private static final @UserIdInt int ARBITRARY_USER_ID = 9876;
+ private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
private static final Instant TIME_LOWER_BOUND = createUnixEpochTime(2009, 1, 1, 12, 0, 0);
private static final TimestampedValue<Instant> ARBITRARY_CLOCK_INITIALIZATION_INFO =
@@ -60,7 +63,7 @@ public class TimeDetectorStrategyImplTest {
createUnixEpochTime(2010, 5, 23, 12, 0, 0));
// This is the traditional ordering for time detection on Android.
- private static final @Origin int [] PROVIDERS_PRIORITY = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+ private static final @Origin int [] ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
/**
* An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO}
@@ -70,41 +73,65 @@ public class TimeDetectorStrategyImplTest {
private static final int ARBITRARY_SLOT_INDEX = 123456;
- private Script mScript;
+ private static final ConfigurationInternal CONFIG_AUTO_DISABLED =
+ new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setSystemClockUpdateThresholdMillis(
+ ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(TIME_LOWER_BOUND)
+ .setOriginPriorities(ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_AUTO_ENABLED =
+ new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setSystemClockUpdateThresholdMillis(
+ ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setAutoTimeLowerBound(TIME_LOWER_BOUND)
+ .setOriginPriorities(ORIGIN_PRIORITIES)
+ .setDeviceHasY2038Issue(true)
+ .setAutoDetectionEnabledSetting(true)
+ .build();
+
+ private FakeEnvironment mFakeEnvironment;
@Before
public void setUp() {
- mScript = new Script();
+ mFakeEnvironment = new FakeEnvironment();
+ mFakeEnvironment.initializeConfig(CONFIG_AUTO_DISABLED);
+ mFakeEnvironment.initializeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO);
}
@Test
public void testSuggestTelephonyTime_autoTimeEnabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
- mScript.simulateTimePassing()
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.simulateTimePassing()
.simulateTelephonyTimeSuggestion(timeSuggestion);
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- mScript.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
+ script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
+ script.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
}
@Test
public void testSuggestTelephonyTime_emptySuggestionIgnored() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, null);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+ script.generateTelephonyTimeSuggestion(slotIndex, null);
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, null);
}
@@ -113,24 +140,26 @@ public class TimeDetectorStrategyImplTest {
public void testSuggestTelephonyTime_systemClockThreshold() {
final int systemClockUpdateThresholdMillis = 1000;
final int clockIncrementMillis = 100;
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeThresholds(systemClockUpdateThresholdMillis)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setSystemClockUpdateThresholdMillis(systemClockUpdateThresholdMillis)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
int slotIndex = ARBITRARY_SLOT_INDEX;
// Send the first time signal. It should be used.
{
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
+ script.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
// Increment the device clocks to simulate the passage of time.
- mScript.simulateTimePassing(clockIncrementMillis);
+ script.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis1 =
- mScript.calculateTimeInMillisForNow(timeSuggestion1.getUnixEpochTime());
+ script.calculateTimeInMillisForNow(timeSuggestion1.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
}
@@ -139,9 +168,9 @@ public class TimeDetectorStrategyImplTest {
// stored, but not used to set the system clock.
{
int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
- TelephonyTimeSuggestion timeSuggestion2 = mScript.generateTelephonyTimeSuggestion(
- slotIndex, mScript.peekSystemClockMillis() + underThresholdMillis);
- mScript.simulateTimePassing(clockIncrementMillis)
+ TelephonyTimeSuggestion timeSuggestion2 = script.generateTelephonyTimeSuggestion(
+ slotIndex, script.peekSystemClockMillis() + underThresholdMillis);
+ script.simulateTimePassing(clockIncrementMillis)
.simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
@@ -149,15 +178,15 @@ public class TimeDetectorStrategyImplTest {
// Now send another time signal, but one that is on the threshold and so should be used.
{
- TelephonyTimeSuggestion timeSuggestion3 = mScript.generateTelephonyTimeSuggestion(
+ TelephonyTimeSuggestion timeSuggestion3 = script.generateTelephonyTimeSuggestion(
slotIndex,
- mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
- mScript.simulateTimePassing(clockIncrementMillis);
+ script.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+ script.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis3 =
- mScript.calculateTimeInMillisForNow(timeSuggestion3.getUnixEpochTime());
+ script.calculateTimeInMillisForNow(timeSuggestion3.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion3)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis3)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion3);
}
@@ -165,8 +194,7 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestTelephonyTime_multipleSlotIndexsAndBucketing() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
// There are 2 slotIndexes in this test. slotIndex1 and slotIndex2 have different opinions
// about the current time. slotIndex1 < slotIndex2 (which is important because the strategy
@@ -179,63 +207,63 @@ public class TimeDetectorStrategyImplTest {
// Make a suggestion with slotIndex2.
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
- mScript.simulateTimePassing();
+ script.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
+ script.simulateTimePassing();
- long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow(
+ long expectedSystemClockMillis = script.calculateTimeInMillisForNow(
slotIndex2TimeSuggestion.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
+ script.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex1, null)
.assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
// Now make a different suggestion with slotIndex1.
{
TelephonyTimeSuggestion slotIndex1TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1Time);
- mScript.simulateTimePassing();
+ script.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1Time);
+ script.simulateTimePassing();
- long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow(
+ long expectedSystemClockMillis = script.calculateTimeInMillisForNow(
slotIndex1TimeSuggestion.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(slotIndex1TimeSuggestion)
+ script.simulateTelephonyTimeSuggestion(slotIndex1TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex1, slotIndex1TimeSuggestion);
}
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
// Make another suggestion with slotIndex2. It should be stored but not used because the
// slotIndex1 suggestion will still "win".
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
- mScript.simulateTimePassing();
+ script.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
+ script.simulateTimePassing();
- mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
+ script.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
// Let enough time pass that slotIndex1's suggestion should now be too old.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.TELEPHONY_BUCKET_SIZE_MILLIS);
+ script.simulateTimePassing(TimeDetectorStrategyImpl.TELEPHONY_BUCKET_SIZE_MILLIS);
// Make another suggestion with slotIndex2. It should be used because the slotIndex1
// is in an older "bucket".
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
- mScript.simulateTimePassing();
+ script.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
+ script.simulateTimePassing();
- long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow(
+ long expectedSystemClockMillis = script.calculateTimeInMillisForNow(
slotIndex2TimeSuggestion.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
+ script.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
@@ -243,13 +271,12 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestTelephonyTime_autoTimeDisabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(false);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing()
+ script.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
+ script.simulateTimePassing()
.simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
@@ -257,29 +284,31 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestTelephonyTime_invalidNitzReferenceTimesIgnored() {
- final int systemClockUpdateThreshold = 2000;
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeThresholds(systemClockUpdateThreshold)
- .pokeAutoTimeDetectionEnabled(true);
+ final int systemClockUpdateThresholdMillis = 2000;
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setSystemClockUpdateThresholdMillis(systemClockUpdateThresholdMillis)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
Instant testTime = ARBITRARY_TEST_TIME;
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
TimestampedValue<Long> unixEpochTime1 = timeSuggestion1.getUnixEpochTime();
// Initialize the strategy / device with a time set from a telephony suggestion.
- mScript.simulateTimePassing();
- long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(unixEpochTime1);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
+ script.simulateTimePassing();
+ long expectedSystemClockMillis1 = script.calculateTimeInMillisForNow(unixEpochTime1);
+ script.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// The Unix epoch time increment should be larger than the system clock update threshold so
// we know it shouldn't be ignored for other reasons.
long validUnixEpochTimeMillis = unixEpochTime1.getValue()
- + (2 * systemClockUpdateThreshold);
+ + (2 * systemClockUpdateThresholdMillis);
// Now supply a new signal that has an obviously bogus reference time : older than the last
// one.
@@ -288,7 +317,7 @@ public class TimeDetectorStrategyImplTest {
referenceTimeBeforeLastSignalMillis, validUnixEpochTimeMillis);
TelephonyTimeSuggestion timeSuggestion2 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime2);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion2)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -300,7 +329,7 @@ public class TimeDetectorStrategyImplTest {
referenceTimeInFutureMillis, validUnixEpochTimeMillis);
TelephonyTimeSuggestion timeSuggestion3 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime3);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion3)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -308,27 +337,26 @@ public class TimeDetectorStrategyImplTest {
long validReferenceTimeMillis = unixEpochTime1.getReferenceTimeMillis() + 100;
TimestampedValue<Long> unixEpochTime4 = new TimestampedValue<>(
validReferenceTimeMillis, validUnixEpochTimeMillis);
- long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(unixEpochTime4);
+ long expectedSystemClockMillis4 = script.calculateTimeInMillisForNow(unixEpochTime4);
TelephonyTimeSuggestion timeSuggestion4 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime4);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion4)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion4);
}
@Test
public void telephonyTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(
+ script.generateTelephonyTimeSuggestion(
slotIndex, suggestedTime);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, null);
}
@@ -336,327 +364,345 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestTelephonyTime_timeDetectionToggled() {
final int clockIncrementMillis = 100;
- final int systemClockUpdateThreshold = 2000;
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeThresholds(systemClockUpdateThreshold)
- .pokeAutoTimeDetectionEnabled(false);
+ final int systemClockUpdateThresholdMillis = 2000;
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setSystemClockUpdateThresholdMillis(systemClockUpdateThresholdMillis)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
TimestampedValue<Long> unixEpochTime1 = timeSuggestion1.getUnixEpochTime();
// Simulate time passing.
- mScript.simulateTimePassing(clockIncrementMillis);
+ script.simulateTimePassing(clockIncrementMillis);
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Simulate more time passing.
- mScript.simulateTimePassing(clockIncrementMillis);
+ script.simulateTimePassing(clockIncrementMillis);
- long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(unixEpochTime1);
+ long expectedSystemClockMillis1 = script.calculateTimeInMillisForNow(unixEpochTime1);
// Turn on auto time detection.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Turn off auto time detection.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Receive another valid time signal.
// It should be on the threshold and accounting for the clock increments.
- TelephonyTimeSuggestion timeSuggestion2 = mScript.generateTelephonyTimeSuggestion(
- slotIndex, mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
+ TelephonyTimeSuggestion timeSuggestion2 = script.generateTelephonyTimeSuggestion(
+ slotIndex, script.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
// Simulate more time passing.
- mScript.simulateTimePassing(clockIncrementMillis);
+ script.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis2 =
- mScript.calculateTimeInMillisForNow(timeSuggestion2.getUnixEpochTime());
+ script.calculateTimeInMillisForNow(timeSuggestion2.getUnixEpochTime());
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion2)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
// Turn on auto time detection.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
}
@Test
public void testSuggestTelephonyTime_maxSuggestionAge() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion telephonySuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(telephonySuggestion.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(telephonySuggestion)
+ script.calculateTimeInMillisForNow(telephonySuggestion.getUnixEpochTime());
+ script.simulateTelephonyTimeSuggestion(telephonySuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis /* expectedNetworkBroadcast */)
.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
// Look inside and check what the strategy considers the current best telephony suggestion.
- assertEquals(telephonySuggestion, mScript.peekBestTelephonySuggestion());
+ assertEquals(telephonySuggestion, script.peekBestTelephonySuggestion());
// Simulate time passing, long enough that telephonySuggestion is now too old.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS);
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS);
// Look inside and check what the strategy considers the current best telephony suggestion.
// It should still be the, it's just no longer used.
- assertNull(mScript.peekBestTelephonySuggestion());
- mScript.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
+ assertNull(script.peekBestTelephonySuggestion());
+ script.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
}
@Test
public void testSuggestManualTime_autoTimeDisabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(false);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
+ script.simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@Test
public void testSuggestManualTime_retainsAutoSignal() {
- // Configure the start state.
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
int slotIndex = ARBITRARY_SLOT_INDEX;
// Simulate a telephony suggestion.
Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
// Simulate the passage of time.
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
- mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+ script.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
+ script.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
// Switch to manual.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
// Simulate a manual suggestion 1 day different from the auto suggestion.
Instant manualTime = testTime.plus(Duration.ofDays(1));
ManualTimeSuggestion manualTimeSuggestion =
- mScript.generateManualTimeSuggestion(manualTime);
- mScript.simulateTimePassing();
+ script.generateManualTimeSuggestion(manualTime);
+ script.simulateTimePassing();
long expectedManualClockMillis =
- mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUnixEpochTime());
- mScript.simulateManualTimeSuggestion(manualTimeSuggestion, true /* expectedResult */)
+ script.calculateTimeInMillisForNow(manualTimeSuggestion.getUnixEpochTime());
+ script.simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, manualTimeSuggestion, true /* expectedResult */)
.verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
// Switch back to auto.
- mScript.simulateAutoTimeDetectionToggle();
+ script.simulateAutoTimeDetectionToggle();
expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
- mScript.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
+ script.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
+ script.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Switch back to manual - nothing should happen to the clock.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
}
@Test
public void manualTimeSuggestion_isIgnored_whenAutoTimeEnabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing()
- .simulateManualTimeSuggestion(timeSuggestion, false /* expectedResult */)
+ script.simulateTimePassing()
+ .simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void manualTimeSuggestion_ignoresTimeLowerBound() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(false);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(suggestedTime);
+ script.generateManualTimeSuggestion(suggestedTime);
- mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ script.simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
.verifySystemClockWasSetAndResetCallTracking(suggestedTime.toEpochMilli());
}
@Test
public void testSuggestNetworkTime_autoTimeEnabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
NetworkTimeSuggestion timeSuggestion =
- mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
+ script.simulateNetworkTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@Test
public void testSuggestNetworkTime_autoTimeDisabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK)
- .pokeAutoTimeDetectionEnabled(false);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setOriginPriorities(ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
NetworkTimeSuggestion timeSuggestion =
- mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing()
+ script.simulateTimePassing()
.simulateNetworkTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
- NetworkTimeSuggestion timeSuggestion = mScript
- .generateNetworkTimeSuggestion(suggestedTime);
+ NetworkTimeSuggestion timeSuggestion =
+ script.generateNetworkTimeSuggestion(suggestedTime);
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ script.simulateNetworkTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestNetworkSuggestion(null);
}
@Test
public void testSuggestGnssTime_autoTimeEnabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_GNSS)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
GnssTimeSuggestion timeSuggestion =
- mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
+ script.simulateGnssTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@Test
public void testSuggestGnssTime_autoTimeDisabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_GNSS)
- .pokeAutoTimeDetectionEnabled(false);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setOriginPriorities(ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
GnssTimeSuggestion timeSuggestion =
- mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing()
+ script.simulateTimePassing()
.simulateGnssTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void testSuggestExternalTime_autoTimeEnabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_EXTERNAL)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_EXTERNAL)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
ExternalTimeSuggestion timeSuggestion =
- mScript.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing();
+ script.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- mScript.simulateExternalTimeSuggestion(timeSuggestion)
+ script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
+ script.simulateExternalTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@Test
public void testSuggestExternalTime_autoTimeDisabled() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_EXTERNAL)
- .pokeAutoTimeDetectionEnabled(false);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setOriginPriorities(ORIGIN_EXTERNAL)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
ExternalTimeSuggestion timeSuggestion =
- mScript.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateTimePassing()
+ script.simulateTimePassing()
.simulateExternalTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void externalTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoOriginPriorities(ORIGIN_EXTERNAL)
- .pokeAutoTimeDetectionEnabled(true);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_EXTERNAL)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
- ExternalTimeSuggestion timeSuggestion = mScript
- .generateExternalTimeSuggestion(suggestedTime);
+ ExternalTimeSuggestion timeSuggestion =
+ script.generateExternalTimeSuggestion(suggestedTime);
- mScript.simulateExternalTimeSuggestion(timeSuggestion)
+ script.simulateExternalTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestExternalSuggestion(null);
}
@Test
public void highPrioritySuggestionsBeatLowerPrioritySuggestions_telephonyNetworkOrigins() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
// Three obviously different times that could not be mistaken for each other.
Instant networkTime1 = ARBITRARY_TEST_TIME;
@@ -668,100 +714,102 @@ public class TimeDetectorStrategyImplTest {
// A network suggestion is made. It should be used because there is no telephony suggestion.
NetworkTimeSuggestion networkTimeSuggestion1 =
- mScript.generateNetworkTimeSuggestion(networkTime1);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateNetworkTimeSuggestion(networkTime1);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
networkTimeSuggestion1.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null)
+ script.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
- assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertNull("No telephony suggestions were made:", mScript.peekBestTelephonySuggestion());
+ assertEquals(networkTimeSuggestion1, script.peekLatestValidNetworkSuggestion());
+ assertNull("No telephony suggestions were made:", script.peekBestTelephonySuggestion());
// Simulate a little time passing.
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.simulateTimePassing(smallTimeIncrementMillis)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now a telephony suggestion is made. Telephony suggestions are prioritized over network
// suggestions so it should "win".
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
telephonyTimeSuggestion.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ script.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
- assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertEquals(telephonyTimeSuggestion, mScript.peekBestTelephonySuggestion());
+ assertEquals(networkTimeSuggestion1, script.peekLatestValidNetworkSuggestion());
+ assertEquals(telephonyTimeSuggestion, script.peekBestTelephonySuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use".
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now another network suggestion is made. Telephony suggestions are prioritized over
// network suggestions so the latest telephony suggestion should still "win".
NetworkTimeSuggestion networkTimeSuggestion2 =
- mScript.generateNetworkTimeSuggestion(networkTime2);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateNetworkTimeSuggestion(networkTime2);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ script.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
- assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertEquals(telephonyTimeSuggestion, mScript.peekBestTelephonySuggestion());
+ assertEquals(networkTimeSuggestion2, script.peekLatestValidNetworkSuggestion());
+ assertEquals(telephonyTimeSuggestion, script.peekBestTelephonySuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to
// be used but networkTimeSuggestion2 is not.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
// NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
// suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle
// to re-run the detection logic. This may change in future but until then we rely on a
// steady stream of suggestions to re-evaluate.
- mScript.verifySystemClockWasNotSetAndResetCallTracking();
+ script.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ script.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
- assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(networkTimeSuggestion2, script.peekLatestValidNetworkSuggestion());
assertNull(
"Telephony suggestion should be expired:",
- mScript.peekBestTelephonySuggestion());
+ script.peekBestTelephonySuggestion());
// Toggle auto-time off and on to force the detection logic to run.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.simulateTimePassing(smallTimeIncrementMillis)
.simulateAutoTimeDetectionToggle();
// Verify the latest network time now wins.
- mScript.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUnixEpochTime()));
+ script.verifySystemClockWasSetAndResetCallTracking(
+ script.calculateTimeInMillisForNow(networkTimeSuggestion2.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ script.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
- assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(networkTimeSuggestion2, script.peekLatestValidNetworkSuggestion());
assertNull(
"Telephony suggestion should still be expired:",
- mScript.peekBestTelephonySuggestion());
+ script.peekBestTelephonySuggestion());
}
@Test
public void highPrioritySuggestionsBeatLowerPrioritySuggestions_networkGnssOrigins() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK, ORIGIN_GNSS);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK, ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
// Three obviously different times that could not be mistaken for each other.
Instant gnssTime1 = ARBITRARY_TEST_TIME;
@@ -773,100 +821,102 @@ public class TimeDetectorStrategyImplTest {
// A gnss suggestion is made. It should be used because there is no network suggestion.
GnssTimeSuggestion gnssTimeSuggestion1 =
- mScript.generateGnssTimeSuggestion(gnssTime1);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateGnssTimeSuggestion(gnssTime1);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateGnssTimeSuggestion(gnssTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
gnssTimeSuggestion1.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(null)
+ script.assertLatestNetworkSuggestion(null)
.assertLatestGnssSuggestion(gnssTimeSuggestion1);
- assertEquals(gnssTimeSuggestion1, mScript.peekLatestValidGnssSuggestion());
- assertNull("No network suggestions were made:", mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(gnssTimeSuggestion1, script.peekLatestValidGnssSuggestion());
+ assertNull("No network suggestions were made:", script.peekLatestValidNetworkSuggestion());
// Simulate a little time passing.
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.simulateTimePassing(smallTimeIncrementMillis)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now a network suggestion is made. Network suggestions are prioritized over gnss
// suggestions so it should "win".
NetworkTimeSuggestion networkTimeSuggestion =
- mScript.generateNetworkTimeSuggestion(networkTime);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateNetworkTimeSuggestion(networkTime);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
networkTimeSuggestion.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestGnssSuggestion(gnssTimeSuggestion1);
- assertEquals(gnssTimeSuggestion1, mScript.peekLatestValidGnssSuggestion());
- assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(gnssTimeSuggestion1, script.peekLatestValidGnssSuggestion());
+ assertEquals(networkTimeSuggestion, script.peekLatestValidNetworkSuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use".
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now another gnss suggestion is made. Network suggestions are prioritized over
// gnss suggestions so the latest network suggestion should still "win".
GnssTimeSuggestion gnssTimeSuggestion2 =
- mScript.generateGnssTimeSuggestion(gnssTime2);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateGnssTimeSuggestion(gnssTime2);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateGnssTimeSuggestion(gnssTimeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestGnssSuggestion(gnssTimeSuggestion2);
- assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
- assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(gnssTimeSuggestion2, script.peekLatestValidGnssSuggestion());
+ assertEquals(networkTimeSuggestion, script.peekLatestValidNetworkSuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to
// be used but networkTimeSuggestion2 is not.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
// NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
// suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle
// to re-run the detection logic. This may change in future but until then we rely on a
// steady stream of suggestions to re-evaluate.
- mScript.verifySystemClockWasNotSetAndResetCallTracking();
+ script.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestGnssSuggestion(gnssTimeSuggestion2);
- assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
+ assertEquals(gnssTimeSuggestion2, script.peekLatestValidGnssSuggestion());
assertNull(
"Network suggestion should be expired:",
- mScript.peekLatestValidNetworkSuggestion());
+ script.peekLatestValidNetworkSuggestion());
// Toggle auto-time off and on to force the detection logic to run.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.simulateTimePassing(smallTimeIncrementMillis)
.simulateAutoTimeDetectionToggle();
// Verify the latest gnss time now wins.
- mScript.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(gnssTimeSuggestion2.getUnixEpochTime()));
+ script.verifySystemClockWasSetAndResetCallTracking(
+ script.calculateTimeInMillisForNow(gnssTimeSuggestion2.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestGnssSuggestion(gnssTimeSuggestion2);
- assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
+ assertEquals(gnssTimeSuggestion2, script.peekLatestValidGnssSuggestion());
assertNull(
"Network suggestion should still be expired:",
- mScript.peekLatestValidNetworkSuggestion());
+ script.peekLatestValidNetworkSuggestion());
}
@Test
public void highPrioritySuggestionsBeatLowerPrioritySuggestions_networkExternalOrigins() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
// Three obviously different times that could not be mistaken for each other.
Instant externalTime1 = ARBITRARY_TEST_TIME;
@@ -878,101 +928,103 @@ public class TimeDetectorStrategyImplTest {
// A external suggestion is made. It should be used because there is no network suggestion.
ExternalTimeSuggestion externalTimeSuggestion1 =
- mScript.generateExternalTimeSuggestion(externalTime1);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateExternalTimeSuggestion(externalTime1);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateExternalTimeSuggestion(externalTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
externalTimeSuggestion1.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(null)
+ script.assertLatestNetworkSuggestion(null)
.assertLatestExternalSuggestion(externalTimeSuggestion1);
- assertEquals(externalTimeSuggestion1, mScript.peekLatestValidExternalSuggestion());
- assertNull("No network suggestions were made:", mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(externalTimeSuggestion1, script.peekLatestValidExternalSuggestion());
+ assertNull("No network suggestions were made:", script.peekLatestValidNetworkSuggestion());
// Simulate a little time passing.
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.simulateTimePassing(smallTimeIncrementMillis)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now a network suggestion is made. Network suggestions are prioritized over external
// suggestions so it should "win".
NetworkTimeSuggestion networkTimeSuggestion =
- mScript.generateNetworkTimeSuggestion(networkTime);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateNetworkTimeSuggestion(networkTime);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(
+ script.calculateTimeInMillisForNow(
networkTimeSuggestion.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestExternalSuggestion(externalTimeSuggestion1);
- assertEquals(externalTimeSuggestion1, mScript.peekLatestValidExternalSuggestion());
- assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(externalTimeSuggestion1, script.peekLatestValidExternalSuggestion());
+ assertEquals(networkTimeSuggestion, script.peekLatestValidNetworkSuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use".
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now another external suggestion is made. Network suggestions are prioritized over
// external suggestions so the latest network suggestion should still "win".
ExternalTimeSuggestion externalTimeSuggestion2 =
- mScript.generateExternalTimeSuggestion(externalTime2);
- mScript.simulateTimePassing(smallTimeIncrementMillis)
+ script.generateExternalTimeSuggestion(externalTime2);
+ script.simulateTimePassing(smallTimeIncrementMillis)
.simulateExternalTimeSuggestion(externalTimeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestExternalSuggestion(externalTimeSuggestion2);
- assertEquals(externalTimeSuggestion2, mScript.peekLatestValidExternalSuggestion());
- assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(externalTimeSuggestion2, script.peekLatestValidExternalSuggestion());
+ assertEquals(networkTimeSuggestion, script.peekLatestValidNetworkSuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use". This should mean that networkTimeSuggestion is now too old to
// be used but externalTimeSuggestion2 is not.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
+ script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2);
// NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
// suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle
// to re-run the detection logic. This may change in future but until then we rely on a
// steady stream of suggestions to re-evaluate.
- mScript.verifySystemClockWasNotSetAndResetCallTracking();
+ script.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestExternalSuggestion(externalTimeSuggestion2);
- assertEquals(externalTimeSuggestion2, mScript.peekLatestValidExternalSuggestion());
+ assertEquals(externalTimeSuggestion2, script.peekLatestValidExternalSuggestion());
assertNull(
"Network suggestion should be expired:",
- mScript.peekLatestValidNetworkSuggestion());
+ script.peekLatestValidNetworkSuggestion());
// Toggle auto-time off and on to force the detection logic to run.
- mScript.simulateAutoTimeDetectionToggle()
+ script.simulateAutoTimeDetectionToggle()
.simulateTimePassing(smallTimeIncrementMillis)
.simulateAutoTimeDetectionToggle();
// Verify the latest external time now wins.
- mScript.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(externalTimeSuggestion2.getUnixEpochTime()));
+ script.verifySystemClockWasSetAndResetCallTracking(
+ script.calculateTimeInMillisForNow(externalTimeSuggestion2.getUnixEpochTime()));
// Check internal state.
- mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ script.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestExternalSuggestion(externalTimeSuggestion2);
- assertEquals(externalTimeSuggestion2, mScript.peekLatestValidExternalSuggestion());
+ assertEquals(externalTimeSuggestion2, script.peekLatestValidExternalSuggestion());
assertNull(
"Network suggestion should still be expired:",
- mScript.peekLatestValidNetworkSuggestion());
+ script.peekLatestValidNetworkSuggestion());
}
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_EXTERNAL,
- ORIGIN_GNSS);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_EXTERNAL,
+ ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant externalTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(15));
@@ -980,15 +1032,15 @@ public class TimeDetectorStrategyImplTest {
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
NetworkTimeSuggestion networkTimeSuggestion =
- mScript.generateNetworkTimeSuggestion(networkTime);
+ script.generateNetworkTimeSuggestion(networkTime);
ExternalTimeSuggestion externalTimeSuggestion =
- mScript.generateExternalTimeSuggestion(externalTime);
+ script.generateExternalTimeSuggestion(externalTime);
GnssTimeSuggestion gnssTimeSuggestion =
- mScript.generateGnssTimeSuggestion(gnssTime);
+ script.generateGnssTimeSuggestion(gnssTime);
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+ script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
- mScript.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ script.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.simulateExternalTimeSuggestion(externalTimeSuggestion)
.simulateGnssTimeSuggestion(gnssTimeSuggestion)
.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
@@ -1001,10 +1053,12 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK,
- ORIGIN_EXTERNAL, ORIGIN_GNSS);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_EXTERNAL,
+ ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -1012,15 +1066,15 @@ public class TimeDetectorStrategyImplTest {
Instant gnssTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
NetworkTimeSuggestion networkTimeSuggestion =
- mScript.generateNetworkTimeSuggestion(networkTime);
+ script.generateNetworkTimeSuggestion(networkTime);
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+ script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
GnssTimeSuggestion gnssTimeSuggestion =
- mScript.generateGnssTimeSuggestion(gnssTime);
+ script.generateGnssTimeSuggestion(gnssTime);
ExternalTimeSuggestion externalTimeSuggestion =
- mScript.generateExternalTimeSuggestion(externalTime);
+ script.generateExternalTimeSuggestion(externalTime);
- mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+ script.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.simulateGnssTimeSuggestion(gnssTimeSuggestion)
.simulateExternalTimeSuggestion(externalTimeSuggestion)
@@ -1033,148 +1087,201 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenHighestPrioritySuggestionIsNotAvailable_fallbacksToNext() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
NetworkTimeSuggestion timeSuggestion =
- mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ script.simulateNetworkTimeSuggestion(timeSuggestion)
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
}
@Test
public void whenHigherPrioritySuggestionsAreNotAvailable_fallbacksToNext() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK,
- ORIGIN_EXTERNAL, ORIGIN_GNSS);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_EXTERNAL,
+ ORIGIN_GNSS)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
GnssTimeSuggestion timeSuggestion =
- mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ script.simulateGnssTimeSuggestion(timeSuggestion)
.assertLatestGnssSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
}
@Test
public void suggestionsFromTelephonyOriginNotInPriorityList_areIgnored() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_NETWORK);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+ script.generateTelephonyTimeSuggestion(slotIndex, testTime);
- mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void suggestionsFromNetworkOriginNotInPriorityList_areIgnored() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
- NetworkTimeSuggestion timeSuggestion = mScript.generateNetworkTimeSuggestion(
+ NetworkTimeSuggestion timeSuggestion = script.generateNetworkTimeSuggestion(
ARBITRARY_TEST_TIME);
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ script.simulateNetworkTimeSuggestion(timeSuggestion)
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void suggestionsFromGnssOriginNotInPriorityList_areIgnored() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
- GnssTimeSuggestion timeSuggestion = mScript.generateGnssTimeSuggestion(
+ GnssTimeSuggestion timeSuggestion = script.generateGnssTimeSuggestion(
ARBITRARY_TEST_TIME);
- mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ script.simulateGnssTimeSuggestion(timeSuggestion)
.assertLatestGnssSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void suggestionsFromExternalOriginNotInPriorityList_areIgnored() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
- ExternalTimeSuggestion timeSuggestion = mScript.generateExternalTimeSuggestion(
+ ExternalTimeSuggestion timeSuggestion = script.generateExternalTimeSuggestion(
ARBITRARY_TEST_TIME);
- mScript.simulateExternalTimeSuggestion(timeSuggestion)
+ script.simulateExternalTimeSuggestion(timeSuggestion)
.assertLatestExternalSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
public void autoOriginPrioritiesList_doesNotAffectManualSuggestion() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(false)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
+ script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
- mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ script.simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
.verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
}
+ @Test
+ public void manualY2038SuggestionsAreRejectedOnAffectedDevices() {
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .setDeviceHasY2038Issue(true)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+ Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+ ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(y2038IssueTime);
+ script.simulateManualTimeSuggestion(
+ ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void telephonyY2038SuggestionsAreRejectedOnAffectedDevices() {
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .setDeviceHasY2038Issue(true)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+ final int slotIndex = 0;
+ Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+ TelephonyTimeSuggestion timeSuggestion =
+ script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void telephonyY2038SuggestionsAreNotRejectedOnUnaffectedDevices() {
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_TELEPHONY)
+ .setDeviceHasY2038Issue(false)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+ final int slotIndex = 0;
+ Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+ TelephonyTimeSuggestion timeSuggestion =
+ script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(y2038IssueTime.toEpochMilli());
+ }
+
/**
* A fake implementation of {@link TimeDetectorStrategyImpl.Environment}. Besides tracking
* changes and behaving like the real thing should, it also asserts preconditions.
*/
private static class FakeEnvironment implements TimeDetectorStrategyImpl.Environment {
- private boolean mAutoTimeDetectionEnabled;
+
+ private ConfigurationInternal mConfigurationInternal;
private boolean mWakeLockAcquired;
private long mElapsedRealtimeMillis;
private long mSystemClockMillis;
- private int mSystemClockUpdateThresholdMillis = 2000;
- private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
- private ConfigurationChangeListener mConfigChangeListener;
+ private ConfigurationChangeListener mConfigurationInternalChangeListener;
// Tracking operations.
private boolean mSystemClockWasSet;
- @Override
- public void setConfigChangeListener(ConfigurationChangeListener listener) {
- mConfigChangeListener = Objects.requireNonNull(listener);
- }
-
- @Override
- public int systemClockUpdateThresholdMillis() {
- return mSystemClockUpdateThresholdMillis;
- }
-
- @Override
- public boolean isAutoTimeDetectionEnabled() {
- return mAutoTimeDetectionEnabled;
+ void initializeConfig(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal = configurationInternal;
}
- @Override
- public Instant autoTimeLowerBound() {
- return TIME_LOWER_BOUND;
+ public void initializeFakeClocks(TimestampedValue<Instant> timeInfo) {
+ pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
+ pokeSystemClockMillis(timeInfo.getValue().toEpochMilli());
}
@Override
- public int[] autoOriginPriorities() {
- return mAutoOriginPriorities;
+ public void setConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+ mConfigurationInternalChangeListener = Objects.requireNonNull(listener);
}
@Override
- public ConfigurationInternal configurationInternal(int userId) {
- throw new UnsupportedOperationException();
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mConfigurationInternal;
}
@Override
@@ -1210,8 +1317,9 @@ public class TimeDetectorStrategyImplTest {
// Methods below are for managing the fake's behavior.
- void pokeSystemClockUpdateThreshold(int thresholdMillis) {
- mSystemClockUpdateThresholdMillis = thresholdMillis;
+ void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal = configurationInternal;
+ mConfigurationInternalChangeListener.onChange();
}
void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
@@ -1222,14 +1330,6 @@ public class TimeDetectorStrategyImplTest {
mSystemClockMillis = systemClockMillis;
}
- void pokeAutoTimeDetectionEnabled(boolean enabled) {
- mAutoTimeDetectionEnabled = enabled;
- }
-
- void pokeAutoOriginPriorities(@Origin int[] autoOriginPriorities) {
- mAutoOriginPriorities = autoOriginPriorities;
- }
-
long peekElapsedRealtimeMillis() {
return mElapsedRealtimeMillis;
}
@@ -1243,11 +1343,6 @@ public class TimeDetectorStrategyImplTest {
mSystemClockMillis += incrementMillis;
}
- void simulateAutoTimeZoneDetectionToggle() {
- mAutoTimeDetectionEnabled = !mAutoTimeDetectionEnabled;
- mConfigChangeListener.onChange();
- }
-
void verifySystemClockNotSet() {
assertFalse(
String.format("System clock was manipulated and set to %s(=%s)",
@@ -1275,7 +1370,6 @@ public class TimeDetectorStrategyImplTest {
*/
private class Script {
- private final FakeEnvironment mFakeEnvironment;
private final TimeDetectorStrategyImpl mTimeDetectorStrategy;
Script() {
@@ -1283,27 +1377,6 @@ public class TimeDetectorStrategyImplTest {
mTimeDetectorStrategy = new TimeDetectorStrategyImpl(mFakeEnvironment);
}
- Script pokeAutoTimeDetectionEnabled(boolean enabled) {
- mFakeEnvironment.pokeAutoTimeDetectionEnabled(enabled);
- return this;
- }
-
- Script pokeFakeClocks(TimestampedValue<Instant> timeInfo) {
- mFakeEnvironment.pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
- mFakeEnvironment.pokeSystemClockMillis(timeInfo.getValue().toEpochMilli());
- return this;
- }
-
- Script pokeThresholds(int systemClockUpdateThreshold) {
- mFakeEnvironment.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
- return this;
- }
-
- Script pokeAutoOriginPriorities(@Origin int... autoOriginPriorities) {
- mFakeEnvironment.pokeAutoOriginPriorities(autoOriginPriorities);
- return this;
- }
-
long peekElapsedRealtimeMillis() {
return mFakeEnvironment.peekElapsedRealtimeMillis();
}
@@ -1312,20 +1385,29 @@ public class TimeDetectorStrategyImplTest {
return mFakeEnvironment.peekSystemClockMillis();
}
+ /**
+ * Simulates the user / user's configuration changing.
+ */
+ Script simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
+ mFakeEnvironment.simulateConfigurationInternalChange(configurationInternal);
+ return this;
+ }
+
Script simulateTelephonyTimeSuggestion(TelephonyTimeSuggestion timeSuggestion) {
mTimeDetectorStrategy.suggestTelephonyTime(timeSuggestion);
return this;
}
Script simulateManualTimeSuggestion(
- ManualTimeSuggestion timeSuggestion, boolean expectedResult) {
+ @UserIdInt int userId, ManualTimeSuggestion timeSuggestion,
+ boolean expectedResult) {
String errorMessage = expectedResult
? "Manual time suggestion was ignored, but expected to be accepted."
: "Manual time suggestion was accepted, but expected to be ignored.";
assertEquals(
errorMessage,
expectedResult,
- mTimeDetectorStrategy.suggestManualTime(timeSuggestion));
+ mTimeDetectorStrategy.suggestManualTime(userId, timeSuggestion));
return this;
}
@@ -1345,7 +1427,15 @@ public class TimeDetectorStrategyImplTest {
}
Script simulateAutoTimeDetectionToggle() {
- mFakeEnvironment.simulateAutoTimeZoneDetectionToggle();
+ ConfigurationInternal configurationInternal =
+ mFakeEnvironment.getCurrentUserConfigurationInternal();
+ boolean autoDetectionEnabledSetting =
+ !configurationInternal.getAutoDetectionEnabledSetting();
+ ConfigurationInternal newConfigurationInternal =
+ new ConfigurationInternal.Builder(configurationInternal)
+ .setAutoDetectionEnabledSetting(autoDetectionEnabledSetting)
+ .build();
+ mFakeEnvironment.simulateConfigurationInternalChange(newConfigurationInternal);
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
index c64ff9e128e6..3de65c19a1a4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -185,7 +185,7 @@ public class WindowOrientationListenerTest {
}
@Override
- public boolean isKeyguardLocked() {
+ public boolean isKeyguardShowingAndNotOccluded() {
return mIsScreenLocked;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 2f054b004d42..8ba9af0d85d0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -840,6 +840,156 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ public void reregisterService_checksAppIsApproved_pkg() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_PACKAGE);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a", 0, true);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_pkg_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_PACKAGE);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_cn() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a/a", 0, true);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_cn_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a/a", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsNotApproved_cn_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("b/b", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertFalse(service.isBound(cn, 0));
+ }
+
+ @Test
public void unbindOtherUserServices() throws PackageManager.NameNotFoundException {
Context context = mock(Context.class);
PackageManager pm = mock(PackageManager.class);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index bd7186e74354..a7d18eeba058 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -126,7 +126,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
when(file.getAbsolutePath()).thenReturn(String.valueOf(i));
AtomicFile af = new AtomicFile(file);
expectedFiles.add(af);
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
cal.add(Calendar.DATE, -1 * retainDays);
@@ -136,7 +136,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
when(file.getName()).thenReturn(String.valueOf(cal.getTimeInMillis() - i));
when(file.getAbsolutePath()).thenReturn(String.valueOf(cal.getTimeInMillis() - i));
AtomicFile af = new AtomicFile(file);
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
// back to today; trim everything a day + old
@@ -162,7 +162,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
when(file.getName()).thenReturn(i + ".bak");
when(file.getAbsolutePath()).thenReturn(i + ".bak");
AtomicFile af = new AtomicFile(file);
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
// trim everything a day+ old
@@ -224,7 +224,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
public void testReadNotificationHistory_readsAllFiles() throws Exception {
for (long i = 10; i >= 5; i--) {
AtomicFile af = mock(AtomicFile.class);
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
mDataBase.readNotificationHistory();
@@ -248,11 +248,11 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
AtomicFile af2 = mock(AtomicFile.class);
when(af2.getBaseFile()).thenReturn(new File(mRootDir, "af2"));
- mDataBase.mHistoryFiles.addLast(af2);
+ mDataBase.mHistoryFiles.add(af2);
mDataBase.readNotificationHistory(null, null, 0);
@@ -269,7 +269,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(true);
@@ -292,7 +292,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(false);
@@ -315,7 +315,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeConversationsFromWrite("pkg", Set.of("convo", "another"))).thenReturn(true);
@@ -338,7 +338,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeConversationsFromWrite("pkg", Set.of("convo"))).thenReturn(false);
@@ -361,7 +361,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeChannelFromWrite("pkg", "channel")).thenReturn(true);
@@ -384,7 +384,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
when(nh.removeChannelFromWrite("pkg", "channel")).thenReturn(false);
@@ -424,7 +424,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
for (int i = 0; i < 5; i++) {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af" + i));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
// Baseline size of history files
assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(5);
@@ -440,7 +440,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
for (int i = 0; i < 5; i++) {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af" + i));
- mDataBase.mHistoryFiles.addLast(af);
+ mDataBase.mHistoryFiles.add(af);
}
// Baseline size of history files
assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(5);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 76d4059eb436..68551d9813d3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -28,6 +28,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeast;
@@ -40,16 +41,23 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
import android.os.UserHandle;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
import android.testing.TestableContext;
import android.util.ArraySet;
@@ -60,6 +68,8 @@ import android.util.Xml;
import com.android.server.UiServiceTestCase;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -457,4 +467,34 @@ public class NotificationListenersTest extends UiServiceTestCase {
mListeners.notifyRemovedLocked(r, 0, rs);
verify(r, never()).getSbn();
}
+
+ @Test
+ public void testImplicitGrant() {
+ String pkg = "pkg";
+ int uid = 9;
+ NotificationChannel channel = new NotificationChannel("id", "name",
+ NotificationManager.IMPORTANCE_HIGH);
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setTimeoutAfter(1);
+
+ StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(uid), null, 0);
+ NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
+
+ ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
+ null, new ComponentName("a", "a"), sbn.getUserId(), false, null, 33, 33);
+ List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
+ when(mListeners.getServices()).thenReturn(services);
+
+ when(mNm.isVisibleToListener(any(), anyInt(), any())).thenReturn(true);
+ when(mNm.makeRankingUpdateLocked(info)).thenReturn(mock(NotificationRankingUpdate.class));
+ mNm.mPackageManagerInternal = mPmi;
+
+ mListeners.notifyPostedLocked(r, null);
+
+ verify(mPmi).grantImplicitAccess(sbn.getUserId(), null, UserHandle.getAppId(33),
+ sbn.getUid(), false, false);
+ }
}
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 0d56975f51d0..ac5bc8621a4c 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -63,7 +63,7 @@ import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -9576,10 +9576,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
assertTrue(mStrongAuthTracker.isInLockDownMode());
- // the notifyRemovedLocked function is called twice due to REASON_CANCEL_ALL.
+ // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
- assertEquals(REASON_CANCEL_ALL, captor.getValue().intValue());
+ assertEquals(REASON_LOCKDOWN, captor.getValue().intValue());
// exit lockdown mode.
mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index dd0c162d8467..a917c57446a9 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -122,8 +122,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
when(mContextSpy.checkPermission("perm2", Process.myPid(), Process.myUid()))
.thenReturn(PERMISSION_GRANTED);
mService.checkSlicePermission(TEST_URI, mContext.getPackageName(),
- mContext.getPackageName(), Process.myPid(),
- Process.myUid(), testPerms);
+ Process.myPid(), Process.myUid(), testPerms);
verify(mContextSpy).checkPermission(eq("perm1"), eq(Process.myPid()), eq(Process.myUid()));
verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid()));
@@ -148,7 +147,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
private void grantSlicePermission() {
doReturn(PERMISSION_GRANTED).when(mService).checkSlicePermission(
- eq(TEST_URI), anyString(), anyString(), anyInt(), anyInt(), any());
+ eq(TEST_URI), anyString(), anyInt(), anyInt(), any());
doReturn(PERMISSION_GRANTED).when(mService).checkAccess(
anyString(), eq(TEST_URI), anyInt(), anyInt());
}
diff --git a/services/tests/wmtests/OWNERS b/services/tests/wmtests/OWNERS
index 0862c05e0ee4..7a128fc60428 100644
--- a/services/tests/wmtests/OWNERS
+++ b/services/tests/wmtests/OWNERS
@@ -1 +1,4 @@
include /services/core/java/com/android/server/wm/OWNERS
+
+# Voice Interaction
+per-file *Assist* = file:/core/java/android/service/voice/OWNERS
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 12e565394926..b8f0b72b24a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1786,13 +1786,16 @@ public class ActivityRecordTests extends WindowTestsBase {
public void testActivityOnCancelFixedRotationTransform() {
final ActivityRecord activity = createActivityWithTask();
final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
+ final RemoteDisplayChangeController remoteDisplayChangeController = activity
+ .mDisplayContent.mRemoteDisplayChangeController;
spyOn(displayRotation);
+ spyOn(remoteDisplayChangeController);
final DisplayContent display = activity.mDisplayContent;
final int originalRotation = display.getRotation();
// Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
- doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
+ doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
anyInt() /* orientation */, anyInt() /* lastRotation */);
// Set to visible so the activity can freeze the screen.
@@ -1830,7 +1833,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Simulate the remote rotation has completed and the configuration doesn't change, then
// the rotated activity should also be restored by clearing the transform.
displayRotation.updateRotationUnchecked(true /* forceUpdate */);
- doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
+ doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
clearInvocations(activity);
display.setFixedRotationLaunchingAppUnchecked(activity);
display.sendNewConfiguration();
@@ -2165,39 +2168,6 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
- public void testSupportsSplitScreenWindowingMode() {
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
- .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
- .build();
-
- // Not allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertFalse(activity.supportsSplitScreenWindowingMode());
-
- // Force resizable
- mAtm.mForceResizableActivities = true;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertTrue(activity.supportsSplitScreenWindowingMode());
-
- // Use development option to allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = -1;
- mAtm.mDevEnableNonResizableMultiWindow = true;
- assertTrue(activity.supportsSplitScreenWindowingMode());
-
- // Always allow non-resizable
- mAtm.mForceResizableActivities = false;
- mAtm.mSupportsNonResizableMultiWindow = 1;
- mAtm.mDevEnableNonResizableMultiWindow = false;
- assertTrue(activity.supportsSplitScreenWindowingMode());
- }
-
- @Test
public void testSupportsFreeform() {
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index b9432753c17f..5be1ecef0360 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -261,12 +261,12 @@ public class ActivityStarterTests extends WindowTestsBase {
PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
doAnswer((inv) -> {
throw new RemoteException();
- }).when(packageManager).activitySupportsIntent(
- eq(source.mActivityComponent), eq(intent), any());
+ }).when(packageManager).activitySupportsIntentAsUser(
+ eq(source.mActivityComponent), eq(intent), any(), anyInt());
} else {
doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
- .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
- eq(intent), any());
+ .when(packageManager).activitySupportsIntentAsUser(
+ eq(source.mActivityComponent), eq(intent), any(), anyInt());
}
} catch (RemoteException e) {
}
@@ -794,7 +794,7 @@ public class ActivityStarterTests extends WindowTestsBase {
// Create adjacent tasks and put one activity under it
final Task parent = new TaskBuilder(mSupervisor).build();
final Task adjacentParent = new TaskBuilder(mSupervisor).build();
- parent.setAdjacentTaskFragment(adjacentParent, true);
+ parent.setAdjacentTaskFragment(adjacentParent);
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setParentTask(parent)
.setCreateTask(true).build();
@@ -1120,28 +1120,27 @@ public class ActivityStarterTests extends WindowTestsBase {
}
@Test
- public void testTargetStackInSplitScreen() {
+ public void testTargetTaskInSplitScreen() {
final ActivityStarter starter =
prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetRootTask */);
final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityOptions options = ActivityOptions.makeBasic();
final ActivityRecord[] outActivity = new ActivityRecord[1];
- // Activity must not land on split-screen stack if currently not in split-screen mode.
+ // Activity must not land on split-screen task if currently not in split-screen mode.
starter.setActivityOptions(options.toBundle())
- .setReason("testWindowingModeOptionsLaunchAdjacent")
+ .setReason("testTargetTaskInSplitScreen")
.setOutActivity(outActivity).execute();
assertThat(outActivity[0].inMultiWindowMode()).isFalse();
- // Move activity to split-screen-primary stack and make sure it has the focus.
+ // Move activity to split-screen-primary task and make sure it has the focus.
TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent());
top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
- top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
+ top.getRootTask().moveToFront("testTargetTaskInSplitScreen");
- // Activity must landed on split-screen-secondary when launch adjacent.
- starter.setActivityOptions(options.toBundle())
- .setReason("testWindowingModeOptionsLaunchAdjacent")
- .setOutActivity(outActivity).execute();
+ // Activity must land on split-screen-secondary when launch adjacent.
+ startActivityInner(starter, outActivity[0], top, options, null /* inTask */,
+ null /* taskFragment*/);
assertThat(outActivity[0].inMultiWindowMode()).isTrue();
}
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 a8571906bb06..20b1120d7d3e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -21,7 +21,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -42,8 +41,8 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
@@ -60,7 +59,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.LocaleList;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
@@ -136,7 +134,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
assertNull(transaction.getLifecycleStateRequest());
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException {
final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
@@ -146,11 +144,16 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
mAtm.mActivityClientController.requestPictureInPictureMode(activity);
- // Check enter no transactions with enter pip requests are made.
- verify(lifecycleManager, times(0)).scheduleTransaction(any());
+ verify(lifecycleManager, atLeast(0))
+ .scheduleTransaction(mClientTransactionCaptor.capture());
+ final ClientTransaction transaction = mClientTransactionCaptor.getValue();
+ // Check that none are enter pip request items.
+ transaction.getCallbacks().forEach(clientTransactionItem -> {
+ assertFalse(clientTransactionItem instanceof EnterPipRequestedItem);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
@@ -159,8 +162,13 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
mAtm.mActivityClientController.requestPictureInPictureMode(activity);
- // Check that no transactions with enter pip requests are made.
- verify(lifecycleManager, times(0)).scheduleTransaction(any());
+ verify(lifecycleManager, atLeast(0))
+ .scheduleTransaction(mClientTransactionCaptor.capture());
+ final ClientTransaction transaction = mClientTransactionCaptor.getValue();
+ // Check that none are enter pip request items.
+ transaction.getCallbacks().forEach(clientTransactionItem -> {
+ assertFalse(clientTransactionItem instanceof EnterPipRequestedItem);
+ });
}
@Test
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 716612c70aef..75ecfd870eb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -21,6 +21,7 @@ import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -34,6 +35,7 @@ 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.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -284,10 +286,14 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
.setCreateActivity(true).build().getTopMostActivity();
activity2.getTask().setResumedActivity(activity2, "test");
- mAtm.mAmInternal.deletePendingTopUid(activity1.getUid(), Long.MAX_VALUE);
+ final int[] pendingTopUid = new int[1];
+ doAnswer(invocation -> {
+ pendingTopUid[0] = invocation.getArgument(0);
+ return null;
+ }).when(mAtm.mAmInternal).addPendingTopUid(anyInt(), anyInt(), any());
clearInvocations(mAtm);
activity1.moveFocusableActivityToTop("test");
- assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid()));
+ assertEquals(activity1.getUid(), pendingTopUid[0]);
verify(mAtm).updateOomAdj();
}
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 77f884c93682..8656a4fecef1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -25,6 +26,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_DREAM_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;
@@ -155,6 +158,32 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
+ public void testDreamActivityOpenTransition() {
+ final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM);
+ mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+ mDisplayContent.mOpeningApps.add(dreamActivity);
+
+ assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_OPEN,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ mDisplayContent.mChangingContainers, null, null, false));
+ }
+
+ @Test
+ public void testDreamActivityCloseTransition() {
+ final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM);
+ mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+ mDisplayContent.mClosingApps.add(dreamActivity);
+
+ assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_CLOSE,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ mDisplayContent.mChangingContainers, null, null, false));
+ }
+
+ @Test
public void testChangeIsNotOverwritten() {
final ActivityRecord behind = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -564,7 +593,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
.setCreatedByOrganizer(true);
final Task splitRoot1 = builder.build();
final Task splitRoot2 = builder.build();
- splitRoot1.setAdjacentTaskFragment(splitRoot2, false /* moveTogether */);
+ splitRoot1.setAdjacentTaskFragment(splitRoot2);
final ActivityRecord activity1 = createActivityRecordWithParentTask(splitRoot1);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 2c1c38f3bee8..873d9f3fc023 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -86,7 +86,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
BackNavigationInfo backNavigationInfo = mBackNavigationController.startBackNavigation(mWm,
- tx, true);
+ tx);
assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
@@ -242,7 +242,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Nullable
private BackNavigationInfo startBackNavigation() {
- return mBackNavigationController.startBackNavigation(mWm, new StubTransaction(), true);
+ return mBackNavigationController.startBackNavigation(mWm, new StubTransaction());
}
@NonNull
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 55a7c1ba0bca..ef84a4bf61c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -293,6 +293,21 @@ public class DimmerTests extends WindowTestsBase {
verify(mTransaction).remove(dimLayer);
}
+ @Test
+ public void testDimmerWithBlurUpdatesTransaction() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
+ mHost.addChild(child, 0);
+
+ final int blurRadius = 50;
+ mDimmer.dimBelow(mTransaction, child, 0, blurRadius);
+ SurfaceControl dimLayer = getDimLayer();
+
+ assertNotNull("Dimmer should have created a surface", dimLayer);
+
+ verify(mTransaction).setBackgroundBlurRadius(dimLayer, blurRadius);
+ verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, -1);
+ }
+
private SurfaceControl getDimLayer() {
return mDimmer.mDimState.mDimLayer;
}
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 07923005c45e..b27060872baa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
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;
@@ -123,8 +124,8 @@ import android.view.ContentRecordingSession;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.IDisplayWindowRotationCallback;
-import android.view.IDisplayWindowRotationController;
+import android.view.IDisplayChangeWindowCallback;
+import android.view.IDisplayChangeWindowController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
import android.view.InsetsState;
@@ -135,6 +136,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
+import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.WindowContainerToken;
@@ -1097,6 +1099,25 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testOrientationBehind() {
+ final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setScreenOrientation(getRotatedOrientation(mDisplayContent)).build();
+ prev.mVisibleRequested = false;
+ final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setScreenOrientation(SCREEN_ORIENTATION_BEHIND).build();
+ assertNotEquals(WindowConfiguration.ROTATION_UNDEFINED,
+ mDisplayContent.rotationForActivityInDifferentOrientation(top));
+
+ mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
+ top.setVisibility(true);
+ mDisplayContent.updateOrientation();
+ // The top uses "behind", so the orientation is decided by the previous.
+ assertEquals(prev, mDisplayContent.getLastOrientationSource());
+ // The top will use the rotation from "prev" with fixed rotation.
+ assertTrue(top.hasFixedRotationTransform());
+ }
+
+ @Test
public void testFixedToUserRotationChanged() {
final DisplayContent dc = createNewDisplay();
dc.getDisplayRotation().setFixedToUserRotation(
@@ -1693,8 +1714,7 @@ public class DisplayContentTests extends WindowTestsBase {
// The condition should reject using fixed rotation because the resumed client in real case
// might get display info immediately. And the fixed rotation adjustments haven't arrived
// client side so the info may be inconsistent with the requested orientation.
- verify(mDisplayContent).handleTopActivityLaunchingInDifferentOrientation(eq(app),
- eq(true) /* checkOpening */);
+ verify(mDisplayContent).updateOrientation(eq(app), anyBoolean());
assertFalse(app.isFixedRotationTransforming());
assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
}
@@ -1782,15 +1802,16 @@ public class DisplayContentTests extends WindowTestsBase {
return true;
}).when(dc).updateDisplayOverrideConfigurationLocked();
final boolean[] called = new boolean[1];
- mWm.mDisplayRotationController =
- new IDisplayWindowRotationController.Stub() {
+ mWm.mDisplayChangeController =
+ new IDisplayChangeWindowController.Stub() {
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- IDisplayWindowRotationCallback callback) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo,
+ IDisplayChangeWindowCallback callback) throws RemoteException {
called[0] = true;
try {
- callback.continueRotateDisplay(toRotation, null);
+ callback.continueDisplayChange(null);
} catch (RemoteException e) {
assertTrue(false);
}
@@ -1824,13 +1845,14 @@ public class DisplayContentTests extends WindowTestsBase {
// Rotate 180 degree so the display doesn't have configuration change. This condition is
// used for the later verification of stop-freezing (without setting mWaitingForConfig).
doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
- mWm.mDisplayRotationController =
- new IDisplayWindowRotationController.Stub() {
+ mWm.mDisplayChangeController =
+ new IDisplayChangeWindowController.Stub() {
@Override
- public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
- IDisplayWindowRotationCallback callback) {
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ DisplayAreaInfo newDisplayAreaInfo,
+ IDisplayChangeWindowCallback callback) throws RemoteException {
try {
- callback.continueRotateDisplay(toRotation, null);
+ callback.continueDisplayChange(null);
} catch (RemoteException e) {
assertTrue(false);
}
@@ -2193,23 +2215,28 @@ public class DisplayContentTests extends WindowTestsBase {
*/
@Test
public void testCreateTestDisplayContentFromDimensions() {
- final int displayWidth = 1000;
- final int displayHeight = 2000;
+ final int displayWidth = 540;
+ final int displayHeight = 960;
+ final int density = 192;
+ final int expectedWidthDp = 450; // = 540/(192/160)
+ final int expectedHeightDp = 800; // = 960/(192/160)
final int windowingMode = WINDOWING_MODE_FULLSCREEN;
final boolean ignoreOrientationRequests = false;
final float fixedOrientationLetterboxRatio = 0;
final DisplayContent testDisplayContent = new TestDisplayContent.Builder(mAtm, displayWidth,
- displayHeight).build();
+ displayHeight).setDensityDpi(density).build();
// test display info
final DisplayInfo di = testDisplayContent.getDisplayInfo();
assertEquals(displayWidth, di.logicalWidth);
assertEquals(displayHeight, di.logicalHeight);
- assertEquals(TestDisplayContent.DEFAULT_LOGICAL_DISPLAY_DENSITY, di.logicalDensityDpi);
+ assertEquals(density, di.logicalDensityDpi);
// test configuration
- final WindowConfiguration windowConfig = testDisplayContent.getConfiguration()
- .windowConfiguration;
+ final Configuration config = testDisplayContent.getConfiguration();
+ assertEquals(expectedWidthDp, config.screenWidthDp);
+ assertEquals(expectedHeightDp, config.screenHeightDp);
+ final WindowConfiguration windowConfig = config.windowConfiguration;
assertEquals(displayWidth, windowConfig.getBounds().width());
assertEquals(displayHeight, windowConfig.getBounds().height());
assertEquals(windowingMode, windowConfig.getWindowingMode());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index dbb7fae548b7..db3a51ca4791 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -39,6 +39,7 @@ import static com.android.server.wm.SizeCompatTests.rotateDisplay;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -168,7 +169,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
- prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
+ prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT,
+ false /* isUnresizable */);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
final Rect taskBounds = new Rect(mFirstTask.getBounds());
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
@@ -209,8 +211,10 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(activityConfigBounds.width()).isEqualTo(activityBounds.width());
assertThat(activityConfigBounds.height()).isEqualTo(activityBounds.height());
assertThat(activitySizeCompatBounds.height()).isEqualTo(newTaskBounds.height());
- assertThat(activitySizeCompatBounds.width()).isEqualTo(
- newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width());
+ final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(activitySizeCompatBounds.width(),
+ newTaskBounds.height() / defaultAspectRatio, 0.5);
}
@Test
@@ -230,8 +234,9 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
- assertThat(activityBounds.height())
- .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
+ final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(activityBounds.height(), dagBounds.width() / defaultAspectRatio, 0.5);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index 1e86522a2307..e502f2fbd173 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -63,7 +63,7 @@ public class LetterboxTest {
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
- /* doubleTapCallback= */ x -> {});
+ /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {});
mTransaction = spy(StubTransaction.class);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index feb1c6fa6b5c..1708ed7d4686 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1229,7 +1229,6 @@ public class RecentTasksTest extends WindowTestsBase {
RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
// The task can be put in split screen even if it is not attached now.
task.removeImmediately();
@@ -1237,7 +1236,6 @@ public class RecentTasksTest extends WindowTestsBase {
info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
// Test non-resizable.
// The non-resizable task cannot be put in split screen because of the config.
@@ -1247,7 +1245,6 @@ public class RecentTasksTest extends WindowTestsBase {
info = mRecentTasks.createRecentTaskInfo(task, true);
assertFalse(info.supportsMultiWindow);
- assertFalse(info.supportsSplitScreenMultiWindow);
// Even if it is not attached, the non-resizable task can be put in split screen as long as
// the device supports it.
@@ -1256,8 +1253,6 @@ public class RecentTasksTest extends WindowTestsBase {
info = mRecentTasks.createRecentTaskInfo(task, true);
assertTrue(info.supportsMultiWindow);
- assertTrue(info.supportsSplitScreenMultiWindow);
-
}
private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) {
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 700fadd61c9a..68079f4a9ac5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -657,7 +657,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mAtm.setBooted(true);
+ setBooted(mAtm);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -685,7 +685,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mAtm.setBooted(true);
+ setBooted(mAtm);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -771,17 +771,10 @@ public class RootWindowContainerTests extends WindowTestsBase {
@Test
public void testNotStartHomeBeforeBoot() {
final int displayId = 1;
- final boolean isBooting = mAtm.mAmInternal.isBooting();
- final boolean isBooted = mAtm.mAmInternal.isBooted();
- try {
- mAtm.mAmInternal.setBooting(false);
- mAtm.mAmInternal.setBooted(false);
- mRootWindowContainer.onDisplayAdded(displayId);
- verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
- } finally {
- mAtm.mAmInternal.setBooting(isBooting);
- mAtm.mAmInternal.setBooted(isBooted);
- }
+ doReturn(false).when(mAtm).isBooting();
+ doReturn(false).when(mAtm).isBooted();
+ mRootWindowContainer.onDisplayAdded(displayId);
+ verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 891b33baf2f1..7f70882a70fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1259,6 +1259,36 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+ public void testOverrideMinAspectRatioLargeForResizableAppInSplitScreen() {
+ setUpDisplaySizeWithApp(/* dw= */ 1000, /* dh= */ 2800);
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, activity.getDisplayContent());
+
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, 1000, 1400);
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode());
+
+ // The per-package override forces the activity into a 16:9 aspect ratio
+ assertEquals(1400, activity.getBounds().height());
+ assertEquals(1400 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+ activity.getBounds().width(), 0.5);
+ }
+
+ @Test
public void testLaunchWithFixedRotationTransform() {
final int dw = 1000;
final int dh = 2500;
@@ -1409,12 +1439,10 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
- // orientation letterbox.
final float fixedOrientationLetterboxAspectRatio = 1.1f;
mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
fixedOrientationLetterboxAspectRatio);
- prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false);
final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
final Rect activityBounds = new Rect(mActivity.getBounds());
@@ -1435,6 +1463,103 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ final float fixedOrientationLetterboxAspectRatio = 1.1f;
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
+ fixedOrientationLetterboxAspectRatio);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // Display shouldn't be rotated.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
+ mActivity.mDisplayContent.getLastOrientation());
+ assertTrue(displayBounds.width() > displayBounds.height());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Letterbox logic should use config_letterboxDefaultMinAspectRatioForUnresizableApps over
+ // config_fixedOrientationLetterboxAspectRatio.
+ assertEquals(displayBounds.height(), activityBounds.height());
+ final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5);
+ }
+
+ @Test
+ public void testSplitAspectRatioForUnresizablePortraitApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(1600, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+
+ assertEquals(displayBounds.height(), activityBounds.height());
+ assertTrue(activityBounds.width() < displayBounds.width() / 2);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ }
+
+ @Test
+ public void testSplitAspectRatioForUnresizableLandscapeApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 1600);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+
+ assertEquals(displayBounds.width(), activityBounds.width());
+ assertTrue(activityBounds.height() < displayBounds.height() / 2);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ }
+
+ @Test
public void
testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
// Set up a display in landscape and ignoring orientation request.
@@ -1908,7 +2033,7 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
- public void testSupportsNonResizableInSplitScreen_fillTaskForSameOrientation() {
+ public void testSupportsNonResizableInSplitScreen_aspectRatioLetterboxInSameOrientation() {
// Support non resizable in multi window
mAtm.mDevEnableNonResizableMultiWindow = true;
setUpDisplaySizeWithApp(1000, 2800);
@@ -1946,7 +2071,12 @@ public class SizeCompatTests extends WindowTestsBase {
// Activity bounds fill split screen.
final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
final Rect letterboxedBounds = new Rect(mActivity.getBounds());
- assertEquals(primarySplitBounds, letterboxedBounds);
+ // Activity is letterboxed for aspect ratio.
+ assertEquals(primarySplitBounds.height(), letterboxedBounds.height());
+ final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(primarySplitBounds.height() / defaultAspectRatio,
+ letterboxedBounds.width(), 0.5);
}
@Test
@@ -1960,7 +2090,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
// Bounds are letterboxed to respect the provided max aspect ratio.
- assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 1100));
+ assertEquals(mActivity.getBounds(), new Rect(0, 850, 1000, 1950));
// Move activity to split screen which has landscape size.
mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents */ false, "test");
@@ -2077,19 +2207,14 @@ public class SizeCompatTests extends WindowTestsBase {
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
-
assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
-
// Rotate to put activity in size compat mode.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
-
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(sizeCompatUnscaled, mActivity.getBounds());
-
// Force activity to scaled down for size compat mode.
resizeDisplay(mTask.mDisplayContent, 700, 1400);
-
assertTrue(mActivity.inSizeCompatMode());
assertScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
@@ -2107,6 +2232,109 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testUpdateResolvedBoundsVerticalPosition_top() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 0, 1400, 700),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 0, 2100, 700),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 0, 700, 350));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_center() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.5f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_invalidMultiplier_defaultToCenter() {
+ // Display configured as (1400, 2800).
+
+ // Below 0.0.
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ -1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+
+ // Above 1.0
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 2.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 525, 700, 875));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_bottom() {
+ // Display configured as (1400, 2800).
+ assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxVerticalPositionMultiplier */ 1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 2100, 1400, 2800),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 700, 2100, 1400),
+ // After the display is resized to (1400, 700).
+ /* sizeCompatScaled */ new Rect(0, 1050, 700, 1400));
+ }
+
+ private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox,
+ Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
+ // Set up a display in portrait and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
+ letterboxVerticalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(sizeCompatUnscaled, mActivity.getBounds());
+
+ // Force activity to scaled down for size compat mode.
+ resizeDisplay(mTask.mDisplayContent, 1400, 700);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ assertScaled();
+ assertEquals(sizeCompatScaled, mActivity.getBounds());
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsVerticalPosition_activityFillParentHeight() {
+ // When activity height equals parent height, multiplier shouldn't have any effect.
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.0f);
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 0.5f);
+ assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxVerticalPositionMultiplier */ 1.0f);
+ }
+
+ @Test
public void testAreBoundsLetterboxed_letterboxedForAspectRatio_returnsTrue() {
setUpDisplaySizeWithApp(1000, 2500);
@@ -2399,6 +2627,23 @@ public class SizeCompatTests extends WindowTestsBase {
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted();
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
+ }
+
+ private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
+ float letterboxVerticalPositionMultiplier) {
+ // Set up a display in portrait and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
+ letterboxVerticalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
@@ -2407,7 +2652,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
- assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
+ assertEquals(new Rect(1050, 0, 1750, 1400), mActivity.getBounds());
}
private static WindowState addWindowToActivity(ActivityRecord activity) {
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 dc9a62554fdb..55cc238e1766 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -66,7 +66,6 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.InputChannel;
-import android.view.Surface;
import android.view.SurfaceControl;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
@@ -77,7 +76,6 @@ import com.android.server.LockGuard;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
-import com.android.server.appop.AppOpsService;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.input.InputManagerService;
@@ -94,10 +92,8 @@ import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
-import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
/**
* JUnit test rule to correctly setting up system services like {@link WindowManagerService}
@@ -125,13 +121,11 @@ public class SystemServicesTestRule implements TestRule {
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
- private ActivityManagerService mAmService;
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
- private Supplier<Surface> mSurfaceFactory = () -> mock(Surface.class);
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
@@ -289,29 +283,9 @@ public class SystemServicesTestRule implements TestRule {
}
private void setUpActivityTaskManagerService() {
- // ActivityManagerService
- mAmService = new ActivityManagerService(new AMTestInjector(mContext), null /* thread */);
- spyOn(mAmService);
- doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
- doNothing().when(mAmService).grantImplicitAccess(
- anyInt(), any(), anyInt(), anyInt());
-
// ActivityManagerInternal
- final ActivityManagerInternal amInternal = mAmService.mInternal;
- spyOn(amInternal);
- doNothing().when(amInternal).trimApplications();
- doNothing().when(amInternal).scheduleAppGcs();
- doNothing().when(amInternal).updateCpuStats();
- doNothing().when(amInternal).updateOomAdj();
- doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
- doNothing().when(amInternal).updateActivityUsageStats(
- any(), anyInt(), anyInt(), any(), any());
- doNothing().when(amInternal).startProcess(
- any(), any(), anyBoolean(), anyBoolean(), any(), any());
- doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt());
- doNothing().when(amInternal).broadcastGlobalConfigurationChanged(anyInt(), anyBoolean());
- doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any());
- doNothing().when(amInternal).reportCurKeyguardUsageEvent(anyBoolean());
+ final ActivityManagerInternal amInternal =
+ mock(ActivityManagerInternal.class, withSettings().stubOnly());
doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
@@ -320,7 +294,9 @@ public class SystemServicesTestRule implements TestRule {
doReturn(false).when(amInternal).isActivityStartsLoggingEnabled();
LocalServices.addService(ActivityManagerInternal.class, amInternal);
- mAtmService = new TestActivityTaskManagerService(mContext, mAmService);
+ final ActivityManagerService amService =
+ mock(ActivityManagerService.class, withSettings().stubOnly());
+ mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
}
@@ -332,9 +308,9 @@ public class SystemServicesTestRule implements TestRule {
// Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
mWmService = WindowManagerService.main(
- mContext, mImService, false, false, wmPolicy, mAtmService,
+ mContext, mImService, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
- () -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
+ (unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
@@ -355,7 +331,7 @@ public class SystemServicesTestRule implements TestRule {
null, null, mTransaction, mWmService.mPowerManagerInternal);
mWmService.onInitReady();
- mAmService.setWindowManager(mWmService);
+ mAtmService.setWindowManager(mWmService);
mWmService.mDisplayEnabled = true;
mWmService.mDisplayReady = true;
// Set configuration for default display
@@ -454,10 +430,6 @@ public class SystemServicesTestRule implements TestRule {
.spiedInstance(sWakeLock).stubOnly());
}
- void setSurfaceFactory(Supplier<Surface> factory) {
- mSurfaceFactory = factory;
- }
-
void cleanupWindowManagerHandlers() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
@@ -618,32 +590,4 @@ public class SystemServicesTestRule implements TestRule {
doReturn(true).when(controller).checkKeyguardVisibility(any());
}
}
-
- // TODO: Can we just mock this?
- private static class AMTestInjector extends ActivityManagerService.Injector {
-
- AMTestInjector(Context context) {
- super(context);
- }
-
- @Override
- public Context getContext() {
- return getInstrumentation().getTargetContext();
- }
-
- @Override
- public AppOpsService getAppOpsService(File file, Handler handler) {
- return null;
- }
-
- @Override
- public Handler getUiHandler(ActivityManagerService service) {
- return UiThread.getHandler();
- }
-
- @Override
- public boolean isNetworkRestrictedForUid(int uid) {
- return false;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index e8f1d2390c34..2a9fcb9d070b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -82,7 +82,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
- adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
+ adjacentRootTask.setAdjacentTaskFragment(rootTask);
taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
Task actualRootTask = taskDisplayArea.getLaunchRootTask(
@@ -108,7 +108,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final Task adjacentRootTask = createTask(
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
- adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
+ adjacentRootTask.setAdjacentTaskFragment(rootTask);
taskDisplayArea.setLaunchRootTask(rootTask,
new int[]{WINDOWING_MODE_MULTI_WINDOW}, new int[]{ACTIVITY_TYPE_STANDARD});
@@ -129,7 +129,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
- adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
+ adjacentRootTask.setAdjacentTaskFragment(rootTask);
taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
final Task actualRootTask = taskDisplayArea.getLaunchRootTask(
@@ -756,7 +756,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
adjacentRootTask.mCreatedByOrganizer = true;
final Task candidateTask = createTaskInRootTask(rootTask, 0 /* userId*/);
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
- adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
+ adjacentRootTask.setAdjacentTaskFragment(rootTask);
// Verify the launch root with candidate task
Task actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED,
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 5340a79f4b94..3ec24b76960f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -24,6 +24,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.testing.Assert.assertThrows;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -32,7 +34,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -43,6 +44,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -78,6 +80,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private static final int TASK_ID = 10;
private TaskFragmentOrganizerController mController;
+ private WindowOrganizerController mWindowOrganizerController;
private TaskFragmentOrganizer mOrganizer;
private TaskFragmentOrganizerToken mOrganizerToken;
private ITaskFragmentOrganizer mIOrganizer;
@@ -87,10 +90,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
private RemoteAnimationDefinition mDefinition;
+ private IBinder mErrorToken;
+ private Rect mTaskFragBounds;
@Before
public void setup() {
- mController = mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController;
+ mWindowOrganizerController = mAtm.mWindowOrganizerController;
+ mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
mOrganizerToken = mOrganizer.getOrganizerToken();
mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
@@ -101,6 +107,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mTransaction = new WindowContainerTransaction();
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
mDefinition = new RemoteAnimationDefinition();
+ mErrorToken = new Binder();
+ final Rect displayBounds = mDisplayContent.getBounds();
+ mTaskFragBounds = new Rect(displayBounds.left, displayBounds.top, displayBounds.centerX(),
+ displayBounds.centerY());
spyOn(mController);
spyOn(mOrganizer);
@@ -221,16 +231,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
- public void testOnTaskFragmentError() throws RemoteException {
- final IBinder errorCallbackToken = new Binder();
+ public void testOnTaskFragmentError() {
final Throwable exception = new IllegalArgumentException("Test exception");
mController.registerOrganizer(mIOrganizer);
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
- errorCallbackToken, exception);
+ mErrorToken, exception);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(exception));
}
@Test
@@ -280,7 +289,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final int uid = Binder.getCallingUid();
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
mController.registerOrganizer(mIOrganizer);
mOrganizer.applyTransaction(mTransaction);
final Task task = createTask(mDisplayContent);
@@ -305,7 +314,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final IBinder temporaryToken = token.getValue();
assertNotEquals(activity.token, temporaryToken);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, temporaryToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(mTaskFragment, activity.getTaskFragment());
// The temporary token can only be used once.
@@ -395,8 +404,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// No lifecycle update when the TaskFragment is not recorded.
verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments
- .put(mFragmentToken, mTaskFragment);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
assertApplyTransactionAllowed(mTransaction);
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
@@ -412,7 +420,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
- mTransaction.setAdjacentRoots(mFragmentWindowToken, token2, false /* moveTogether */);
+ mTransaction.setAdjacentRoots(mFragmentWindowToken, token2);
assertApplyTransactionDisallowed(mTransaction);
@@ -466,23 +474,23 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Fail to create TaskFragment when the task uid is different from caller.
activity.info.applicationInfo.uid = uid;
activity.getTask().effectiveUid = uid + 1;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
// Fail to create TaskFragment when the task uid is different from owner activity.
activity.info.applicationInfo.uid = uid + 1;
activity.getTask().effectiveUid = uid;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
// Successfully created a TaskFragment for same uid.
activity.info.applicationInfo.uid = uid;
activity.getTask().effectiveUid = uid;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@Test
@@ -519,7 +527,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setParentTask(task)
.setFragmentToken(mFragmentToken)
.build();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments
+ mWindowOrganizerController.mLaunchTaskFragments
.put(mFragmentToken, mTaskFragment);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
@@ -549,8 +557,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setOrganizer(mOrganizer)
.createActivityCount(1)
.build();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
+ mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
+ mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
final ActivityRecord activity0 = tf0.getTopMostActivity();
final ActivityRecord activity1 = tf1.getTopMostActivity();
@@ -558,7 +566,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
mDisplayContent.setFocusedApp(activityInOtherTask);
mTransaction.requestFocusOnTaskFragment(token0);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
@@ -566,7 +574,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
activity0.setState(ActivityRecord.State.PAUSED, "test");
activity1.setState(ActivityRecord.State.RESUMED, "test");
mDisplayContent.setFocusedApp(activity1);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activity1, mDisplayContent.mFocusedApp);
@@ -574,7 +582,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// has a resumed activity.
activity0.setState(ActivityRecord.State.RESUMED, "test");
mDisplayContent.setFocusedApp(activity1);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activity0, mDisplayContent.mFocusedApp);
}
@@ -583,54 +591,51 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
public void testTaskFragmentInPip_startActivityInTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = mTaskFragment.getTopMostActivity();
- final IBinder errorToken = new Binder();
spyOn(mAtm.getActivityStartController());
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to start activity in a TaskFragment that is in a PIP Task.
mTransaction.startActivityInTaskFragment(
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
- any(), any(), anyInt(), anyInt());
+ any(), any(), anyInt(), anyInt(), any());
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
+ eq(mErrorToken), any(IllegalArgumentException.class));
}
@Test
public void testTaskFragmentInPip_reparentActivityToTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = createActivityRecord(mDisplayContent);
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to reparent activity to a TaskFragment that is in a PIP Task.
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
assertNull(activity.getOrganizedTaskFragment());
}
@Test
public void testTaskFragmentInPip_setAdjacentTaskFragment() {
setupTaskFragmentInPip();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to set adjacent on a TaskFragment that is in a PIP Task.
mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
null /* options */)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
- verify(mTaskFragment, never()).setAdjacentTaskFragment(any(), anyBoolean());
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
+ verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
}
@Test
@@ -640,47 +645,45 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
ACTIVITY_TYPE_STANDARD);
final ActivityRecord activity = createActivityRecord(pipTask);
final IBinder fragmentToken = new Binder();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to create TaskFragment in a PIP Task.
createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
- mTransaction.setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mTransaction.setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@Test
public void testTaskFragmentInPip_deleteTaskFragment() {
setupTaskFragmentInPip();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to delete a TaskFragment that is in a PIP Task.
mTransaction.deleteTaskFragment(mFragmentWindowToken)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
- assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
+ assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
// Allow organizer to delete empty TaskFragment for cleanup.
final Task task = mTaskFragment.getTask();
mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
assertNull(task.getTopChild());
}
@Test
public void testTaskFragmentInPip_setConfig() {
setupTaskFragmentInPip();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Set bounds is ignored on a TaskFragment that is in a PIP Task.
mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
@@ -832,14 +835,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final IBinder fragmentToken = new Binder();
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
- final TaskFragment taskFragment = mAtm.mWindowOrganizerController
- .getTaskFragment(fragmentToken);
+ final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
assertNotNull(taskFragment);
taskFragment.removeImmediately();
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
/**
@@ -902,6 +904,101 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
assertApplyTransactionDisallowed(mTransaction);
}
+ // TODO(b/232871351): add test for minimum dimension violation in startActivityInTaskFragment
+ @Test
+ public void testMinDimensionViolation_ReparentActivityToTaskFragment() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(task);
+ // Make minWidth/minHeight exceeds the TaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(mTaskFragBounds)
+ .build();
+ doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Reparent activity to mTaskFragment, which is smaller than activity's
+ // minimum dimensions.
+ mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class));
+ }
+
+ @Test
+ public void testMinDimensionViolation_ReparentChildren() {
+ final Task task = createTask(mDisplayContent);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ final IBinder oldFragToken = new Binder();
+ final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setFragmentToken(oldFragToken)
+ .setOrganizer(mOrganizer)
+ .build();
+ final ActivityRecord activity = oldTaskFrag.getTopMostActivity();
+ // Make minWidth/minHeight exceeds mTaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(mTaskFragBounds)
+ .build();
+ doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
+ mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Reparent oldTaskFrag's children to mTaskFragment, which is smaller than activity's
+ // minimum dimensions.
+ mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
+ mTaskFragment.mRemoteToken.toWindowContainerToken())
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class));
+ }
+
+ @Test
+ public void testMinDimensionViolation_SetBounds() {
+ final Task task = createTask(mDisplayContent);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(new Rect(0, 0, mTaskFragBounds.right * 2, mTaskFragBounds.bottom * 2))
+ .build();
+ final ActivityRecord activity = mTaskFragment.getTopMostActivity();
+ // Make minWidth/minHeight exceeds the TaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Shrink the TaskFragment to mTaskFragBounds to make its bounds smaller than activity's
+ // minimum dimensions.
+ mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertWithMessage("setBounds must not be performed.")
+ .that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
+ }
+
/**
* Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
* {@link WindowOrganizerController#applyTransaction} to apply the transaction,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 3ed484ac7391..228cb65aab38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -202,7 +202,7 @@ public class TaskFragmentTest extends WindowTestsBase {
doReturn(true).when(primaryActivity).supportsPictureInPicture();
doReturn(false).when(secondaryActivity).supportsPictureInPicture();
- primaryTf.setAdjacentTaskFragment(secondaryTf, false /* moveAdjacentTogether */);
+ primaryTf.setAdjacentTaskFragment(secondaryTf);
primaryActivity.setState(RESUMED, "test");
secondaryActivity.setState(RESUMED, "test");
@@ -448,7 +448,7 @@ public class TaskFragmentTest extends WindowTestsBase {
.setOrganizer(mOrganizer)
.setFragmentToken(new Binder())
.build();
- tf0.setAdjacentTaskFragment(tf1, false /* moveAdjacentTogether */);
+ tf0.setAdjacentTaskFragment(tf1);
tf0.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
tf1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
task.setBounds(0, 0, 1200, 1000);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 202168bae869..46e21f1ffdbc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -31,7 +31,6 @@ 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_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
@@ -60,7 +59,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.clearInvocations;
@@ -497,34 +495,6 @@ public class TaskTests extends WindowTestsBase {
assertEquals(reqBounds.height(), task.getBounds().height());
}
- /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
- @Test
- public void testBoundsOnModeChangeFreeformToFullscreen() {
- DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
- Task rootTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- Task task = rootTask.getBottomMostTask();
- task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
- DisplayInfo info = new DisplayInfo();
- display.mDisplay.getDisplayInfo(info);
- final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
- final Rect freeformBounds = new Rect(fullScreenBounds);
- freeformBounds.inset((int) (freeformBounds.width() * 0.2),
- (int) (freeformBounds.height() * 0.2));
- task.setBounds(freeformBounds);
-
- assertEquals(freeformBounds, task.getBounds());
-
- // FULLSCREEN inherits bounds
- rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertEquals(fullScreenBounds, task.getBounds());
- assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
-
- // FREEFORM restores bounds
- rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertEquals(freeformBounds, task.getBounds());
- }
-
/**
* Tests that a task with forced orientation has orientation-consistent bounds within the
* parent.
@@ -590,6 +560,7 @@ public class TaskTests extends WindowTestsBase {
// FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ rootTask.setBounds(null);
assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
assertEquals(fullScreenBoundsPort, task.getBounds());
@@ -667,8 +638,6 @@ public class TaskTests extends WindowTestsBase {
final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
final Configuration inOutConfig = new Configuration();
final Configuration parentConfig = new Configuration();
- final int longSide = 1200;
- final int shortSide = 600;
final Rect parentBounds = new Rect(0, 0, 250, 500);
final Rect parentAppBounds = new Rect(0, 0, 250, 480);
parentConfig.windowConfiguration.setBounds(parentBounds);
@@ -689,14 +658,17 @@ public class TaskTests extends WindowTestsBase {
// If bounds are overridden, config properties should be made to match. Surface hierarchy
// will crop for policy.
inOutConfig.setToDefaults();
+ final int longSide = 960;
+ final int shortSide = 540;
+ parentConfig.densityDpi = 192;
final Rect largerPortraitBounds = new Rect(0, 0, shortSide, longSide);
inOutConfig.windowConfiguration.setBounds(largerPortraitBounds);
task.computeConfigResourceOverrides(inOutConfig, parentConfig);
// The override bounds are beyond the parent, the out appBounds should not be intersected
// by parent appBounds.
assertEquals(largerPortraitBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals(longSide, inOutConfig.screenHeightDp * parentConfig.densityDpi / 160);
- assertEquals(shortSide, inOutConfig.screenWidthDp * parentConfig.densityDpi / 160);
+ assertEquals(800, inOutConfig.screenHeightDp); // 960/(192/160) = 800
+ assertEquals(450, inOutConfig.screenWidthDp); // 540/(192/160) = 450
inOutConfig.setToDefaults();
// Landscape bounds.
@@ -716,16 +688,17 @@ public class TaskTests extends WindowTestsBase {
// Without limiting to be inside the parent bounds, the out screen size should keep relative
// to the input bounds.
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
- final ActivityRecord.CompatDisplayInsets compatIntsets =
+ final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
display, activity, /* fixedOrientationBounds= */ null);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenHeightDp);
- assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenWidthDp);
+ final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ final int expectedHeightDp = (int) ((shortSide - statusBarHeight) / density + 0.5f);
+ assertEquals(expectedHeightDp, inOutConfig.screenHeightDp);
+ final int expectedWidthDp = (int) (longSide / density + 0.5f);
+ assertEquals(expectedWidthDp, inOutConfig.screenWidthDp);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
}
@@ -1443,25 +1416,6 @@ public class TaskTests extends WindowTestsBase {
}
@Test
- public void testMoveToFront_moveAdjacentTask() {
- final Task task1 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- final Task task2 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- spyOn(task2);
-
- task1.setAdjacentTaskFragment(task2, false /* moveTogether */);
- task1.moveToFront("" /* reason */);
- verify(task2, never()).moveToFrontInner(anyString(), isNull());
-
- // Reset adjacent tasks to move together.
- task1.setAdjacentTaskFragment(null, false /* moveTogether */);
- task1.setAdjacentTaskFragment(task2, true /* moveTogether */);
- task1.moveToFront("" /* reason */);
- verify(task2).moveToFrontInner(anyString(), isNull());
- }
-
- @Test
public void testResumeTask_doNotResumeTaskFragmentBehindTranslucent() {
final Task task = createTask(mDisplayContent);
final TaskFragment tfBehind = createTaskFragmentWithParentTask(
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ea98b6b17e83..92457c73b315 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -26,7 +26,6 @@ import android.os.IBinder;
import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.WakeReason;
import android.util.proto.ProtoOutputStream;
-import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -50,8 +49,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void init(Context context, IWindowManager windowManager,
- WindowManagerFuncs windowManagerFuncs) {
+ public void init(Context context, WindowManagerFuncs windowManagerFuncs) {
}
public void setDefaultDisplay(DisplayContentInfo displayContentInfo) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 6c1c0865446e..234bfa7ad772 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -85,9 +85,14 @@ import java.util.function.Function;
@Presubmit
@RunWith(WindowTestRunner.class)
public class TransitionTests extends WindowTestsBase {
+ final SurfaceControl.Transaction mMockT = mock(SurfaceControl.Transaction.class);
private Transition createTestTransition(int transitType) {
- TransitionController controller = mock(TransitionController.class);
+ TransitionTracer tracer = mock(TransitionTracer.class);
+ final TransitionController controller = new TransitionController(
+ mock(ActivityTaskManagerService.class), mock(TaskSnapshotController.class),
+ mock(TransitionTracer.class));
+
final BLASTSyncEngine sync = createTestBLASTSyncEngine();
final Transition t = new Transition(transitType, 0 /* flags */, controller, sync);
t.startCollecting(0 /* timeoutMs */);
@@ -121,7 +126,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(oldTask);
participants.add(newTask);
ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
@@ -129,7 +135,7 @@ public class TransitionTests extends WindowTestsBase {
participants.add(opening);
participants.add(closing);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -137,7 +143,7 @@ public class TransitionTests extends WindowTestsBase {
// Check combined prune and promote
participants.remove(newTask);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -145,7 +151,7 @@ public class TransitionTests extends WindowTestsBase {
// Check multi promote
participants.remove(oldTask);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -186,7 +192,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(opening);
participants.add(opening2);
ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
@@ -195,7 +202,7 @@ public class TransitionTests extends WindowTestsBase {
// Check that unchanging but visible descendant of sibling prevents promotion
participants.remove(opening2);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
assertNotNull(info.getChange(newNestedTask.mRemoteToken.toWindowContainerToken()));
assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -232,7 +239,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(showing);
participants.add(showing2);
ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
assertEquals(1, info.getChanges().size());
assertEquals(transit, info.getType());
assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
@@ -240,14 +248,14 @@ public class TransitionTests extends WindowTestsBase {
// Check that organized tasks get reported even if not top
makeTaskOrganized(showTask);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
assertNotNull(info.getChange(showTask.mRemoteToken.toWindowContainerToken()));
// Even if DisplayArea explicitly participating
participants.add(tda);
targets = Transition.calculateTargets(participants, changes);
- info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ info = Transition.calculateTransitionInfo(transit, flags, targets, changes, mMockT);
assertEquals(2, info.getChanges().size());
}
@@ -271,7 +279,7 @@ public class TransitionTests extends WindowTestsBase {
ArrayList<WindowContainer> targets = Transition.calculateTargets(
transition.mParticipants, transition.mChanges);
TransitionInfo info = Transition.calculateTransitionInfo(
- 0, 0, targets, transition.mChanges);
+ 0, 0, targets, transition.mChanges, mMockT);
assertEquals(2, info.getChanges().size());
// There was an existence change on open, so it should be OPEN rather than SHOW
assertEquals(TRANSIT_OPEN,
@@ -308,7 +316,7 @@ public class TransitionTests extends WindowTestsBase {
ArrayList<WindowContainer> targets = Transition.calculateTargets(
transition.mParticipants, transition.mChanges);
TransitionInfo info = Transition.calculateTransitionInfo(
- 0, 0, targets, transition.mChanges);
+ 0, 0, targets, transition.mChanges, mMockT);
assertEquals(taskCount, info.getChanges().size());
// verify order is top-to-bottem
for (int i = 0; i < taskCount; ++i) {
@@ -358,7 +366,7 @@ public class TransitionTests extends WindowTestsBase {
ArrayList<WindowContainer> targets = Transition.calculateTargets(
transition.mParticipants, transition.mChanges);
TransitionInfo info = Transition.calculateTransitionInfo(
- 0, 0, targets, transition.mChanges);
+ 0, 0, targets, transition.mChanges, mMockT);
// verify that wallpaper is at bottom
assertEquals(taskCount + 1, info.getChanges().size());
// The wallpaper is not organized, so it won't have a token; however, it will be marked
@@ -392,7 +400,7 @@ public class TransitionTests extends WindowTestsBase {
ArrayList<WindowContainer> targets = Transition.calculateTargets(
transition.mParticipants, transition.mChanges);
TransitionInfo info = Transition.calculateTransitionInfo(
- 0, 0, targets, transition.mChanges);
+ 0, 0, targets, transition.mChanges, mMockT);
// The wallpaper is not organized, so it won't have a token; however, it will be marked
// as IS_WALLPAPER
assertEquals(FLAG_IS_WALLPAPER, info.getChanges().get(0).getFlags());
@@ -474,7 +482,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(changeTask);
final ArrayList<WindowContainer> targets =
Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
// Root changes should always be considered independent
assertTrue(isIndependent(
info.getChange(openTask.mRemoteToken.toWindowContainerToken()), info));
@@ -526,7 +535,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(oldTask);
participants.add(newTask);
ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
@@ -566,7 +576,8 @@ public class TransitionTests extends WindowTestsBase {
participants.add(oldTask);
participants.add(newTask);
ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
- TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes,
+ mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
@@ -577,7 +588,7 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testTimeout() {
final TransitionController controller = new TransitionController(mAtm,
- mock(TaskSnapshotController.class));
+ mock(TaskSnapshotController.class), mock(TransitionTracer.class));
final BLASTSyncEngine sync = new BLASTSyncEngine(mWm);
final CountDownLatch latch = new CountDownLatch(1);
// When the timeout is reached, it will finish the sync-group and notify transaction ready.
@@ -608,7 +619,7 @@ public class TransitionTests extends WindowTestsBase {
final int flags = 0;
final TransitionInfo info = Transition.calculateTransitionInfo(transition.mType, flags,
Transition.calculateTargets(transition.mParticipants, transition.mChanges),
- transition.mChanges);
+ transition.mChanges, mMockT);
transition.abort();
return info.getChanges().get(0);
};
@@ -814,8 +825,11 @@ public class TransitionTests extends WindowTestsBase {
player.onTransactionReady(mDisplayContent.getSyncTransaction());
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+ final RemoteDisplayChangeController displayChangeController = mDisplayContent
+ .mRemoteDisplayChangeController;
spyOn(displayRotation);
- doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
+ spyOn(displayChangeController);
+ doReturn(true).when(displayChangeController).isWaitingForRemoteDisplayChange();
doReturn(prevRotation + 1).when(displayRotation).rotationForOrientation(
anyInt() /* orientation */, anyInt() /* lastRotation */);
// Rotation update is skipped while the recents animation is running.
@@ -831,7 +845,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testIntermediateVisibility() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
- final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* appThread */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -895,7 +910,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testTransientLaunch() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
- final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* appThread */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -955,6 +971,30 @@ public class TransitionTests extends WindowTestsBase {
verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
}
+ @Test
+ public void testNotReadyPushPop() {
+ final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
+ final ITransitionPlayer player = new ITransitionPlayer.Default();
+ controller.registerTransitionPlayer(player, null /* appThread */);
+ final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
+
+ // Start out with task2 visible and set up a transition that closes task2 and opens task1
+ final Task task1 = createTask(mDisplayContent);
+ openTransition.collectExistenceChange(task1);
+
+ assertFalse(openTransition.allReady());
+
+ openTransition.setAllReady();
+
+ openTransition.deferTransitionReady();
+ assertFalse(openTransition.allReady());
+
+ openTransition.continueTransitionReady();
+ assertTrue(openTransition.allReady());
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 40ca2506fab1..08bad70a1411 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -522,7 +522,10 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode());
- assertEquals(WINDOWING_MODE_PINNED, rootTask.getWindowingMode());
+ // Get the root task from the PIP activity record again, since the PIP root task may have
+ // changed when the activity entered PIP mode.
+ final Task pipRootTask = record.getRootTask();
+ assertEquals(WINDOWING_MODE_PINNED, pipRootTask.getWindowingMode());
}
@Test
@@ -687,7 +690,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final RunningTaskInfo info2 = task2.getTaskInfo();
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setAdjacentRoots(info1.token, info2.token, false /* moveTogether */);
+ wct.setAdjacentRoots(info1.token, info2.token);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(task1.getAdjacentTaskFragment(), task2);
assertEquals(task2.getAdjacentTaskFragment(), task1);
@@ -697,8 +700,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, task1);
- task1.setAdjacentTaskFragment(null, false /* moveTogether */);
- task2.setAdjacentTaskFragment(null, false /* moveTogether */);
+ task1.setAdjacentTaskFragment(null);
+ task2.setAdjacentTaskFragment(null);
wct = new WindowContainerTransaction();
wct.clearLaunchAdjacentFlagRoot(info1.token);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
@@ -1015,6 +1018,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ActivityRecord record = createActivityRecordWithParentTask(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
record.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ record.setPictureInPictureParams(new PictureInPictureParams.Builder()
+ .setAutoEnterEnabled(true).build());
spyOn(record);
doReturn(true).when(record).checkEnterPictureInPictureState(any(), anyBoolean());
@@ -1499,7 +1504,11 @@ public class WindowOrganizerTests extends WindowTestsBase {
verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
clearInvocations(mWm.mAtmService.mRootWindowContainer);
- t.setWindowingMode(wct, WINDOWING_MODE_FULLSCREEN);
+ // The token for the PIP root task may have changed when the task entered PIP mode, so do
+ // not reuse the one from above.
+ final WindowContainerToken newToken =
+ record.getRootTask().mRemoteToken.toWindowContainerToken();
+ t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 746f2b50ac3a..3abf7ce665ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -39,24 +40,30 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.ActivityManager;
+import android.app.ClientTransactionHandler;
import android.app.IApplicationThread;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.LocaleList;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mockito;
@@ -282,6 +289,39 @@ public class WindowProcessControllerTests extends WindowTestsBase {
}
@Test
+ public void testCachedStateConfigurationChange() throws RemoteException {
+ final ClientLifecycleManager clientManager = mAtm.getLifecycleManager();
+ doNothing().when(clientManager).scheduleTransaction(any(), any());
+ final IApplicationThread thread = mWpc.getThread();
+ final Configuration newConfig = new Configuration(mWpc.getConfiguration());
+ newConfig.densityDpi += 100;
+ // Non-cached state will send the change directly.
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ clearInvocations(clientManager);
+ mWpc.onConfigurationChanged(newConfig);
+ verify(clientManager).scheduleTransaction(eq(thread), any());
+
+ // Cached state won't send the change.
+ clearInvocations(clientManager);
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+ newConfig.densityDpi += 100;
+ mWpc.onConfigurationChanged(newConfig);
+ verify(clientManager, never()).scheduleTransaction(eq(thread), any());
+
+ // Cached -> non-cached will send the previous deferred config immediately.
+ mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_RECEIVER);
+ final ArgumentCaptor<ConfigurationChangeItem> captor =
+ ArgumentCaptor.forClass(ConfigurationChangeItem.class);
+ verify(clientManager).scheduleTransaction(eq(thread), captor.capture());
+ final ClientTransactionHandler client = mock(ClientTransactionHandler.class);
+ captor.getValue().preExecute(client, null /* token */);
+ final ArgumentCaptor<Configuration> configCaptor =
+ ArgumentCaptor.forClass(Configuration.class);
+ verify(client).updatePendingConfiguration(configCaptor.capture());
+ assertEquals(newConfig, configCaptor.getValue());
+ }
+
+ @Test
public void testComputeOomAdjFromActivities() {
final ActivityRecord activity = createActivityRecord(mWpc);
activity.mVisibleRequested = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 724204f79eab..378aff81ec3c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -673,6 +673,14 @@ public class WindowStateTests extends WindowTestsBase {
// Keyguard host window should be always contained. The drawn app or app with starting
// window are unnecessary to draw.
assertEquals(Arrays.asList(keyguardHostWindow, startingWindow), outWaitingForDrawn);
+
+ // No need to wait for a window of invisible activity even if the window has surface.
+ final WindowState invisibleApp = mAppWindow;
+ invisibleApp.mActivityRecord.mVisibleRequested = false;
+ invisibleApp.mActivityRecord.allDrawn = false;
+ outWaitingForDrawn.clear();
+ invisibleApp.requestDrawIfNeeded(outWaitingForDrawn);
+ assertTrue(outWaitingForDrawn.isEmpty());
}
@UseTestDisplay(addWindows = W_ABOVE_ACTIVITY)
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 9957d05d0a52..50fa4cc9eb7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -229,14 +229,28 @@ class WindowTestsBase extends SystemServiceTestsBase {
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(0);
- // Ensure letterbox position multiplier is not overridden on any device target.
+ // Ensure letterbox horizontal position multiplier is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
- // Ensure letterbox reachability treatment isn't overridden on any device target.
- // {@link com.android.internal.R.bool.config_letterboxIsReachabilityEnabled},
+ // Ensure letterbox vertical position multiplier is not overridden on any device target.
+ // {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
+ // may be set on some device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
+ // Ensure letterbox horizontal reachability treatment isn't overridden on any device target.
+ // {@link com.android.internal.R.bool.config_letterboxIsHorizontalReachabilityEnabled},
// may be set on some device form factors.
- mAtm.mWindowManager.mLetterboxConfiguration.setIsReachabilityEnabled(false);
+ mAtm.mWindowManager.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(false);
+ // Ensure letterbox vertical reachability treatment isn't overridden on any device target.
+ // {@link com.android.internal.R.bool.config_letterboxIsVerticalReachabilityEnabled},
+ // may be set on some device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(false);
+ // Ensure aspect ratio for unresizable apps isn't overridden on any device target.
+ // {@link com.android.internal.R.bool
+ // .config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}, may be set on some
+ // device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(false);
checkDeviceSpecificOverridesNotApplied();
}
@@ -246,7 +260,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
// Revert back to device overrides.
mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
- mAtm.mWindowManager.mLetterboxConfiguration.resetIsReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
}
/**
@@ -1199,6 +1217,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
@Nullable
private TaskFragmentOrganizer mOrganizer;
private IBinder mFragmentToken;
+ private Rect mBounds;
TaskFragmentBuilder(ActivityTaskManagerService service) {
mAtm = service;
@@ -1235,6 +1254,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ TaskFragmentBuilder setBounds(@Nullable Rect bounds) {
+ mBounds = bounds;
+ return this;
+ }
+
TaskFragment build() {
SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
@@ -1262,6 +1286,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
mOrganizer.getOrganizerToken(), DEFAULT_TASK_FRAGMENT_ORGANIZER_UID,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
}
+ if (mBounds != null && !mBounds.isEmpty()) {
+ taskFragment.setBounds(mBounds);
+ }
spyOn(taskFragment);
return taskFragment;
}
@@ -1541,7 +1568,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mSecondary = mService.mTaskOrganizerController.createRootTask(
display, WINDOWING_MODE_MULTI_WINDOW, null);
- mPrimary.setAdjacentTaskFragment(mSecondary, true);
+ mPrimary.setAdjacentTaskFragment(mSecondary);
display.getDefaultTaskDisplayArea().setLaunchAdjacentFlagRootTask(mSecondary);
final Rect primaryBounds = new Rect();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2df1d23c0497..77fca451547d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -328,7 +328,6 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeWindow, imeSystemOverlayTarget);
assertWindowHigher(mImeWindow, mChildAppWindowAbove);
assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mImeWindow, mDockedDividerWindow);
// The IME has a higher base layer than the status bar so we may expect it to go
// above the status bar once they are both in the Non-App layer, as past versions of this
@@ -349,7 +348,6 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeWindow, mChildAppWindowAbove);
assertWindowHigher(mImeWindow, mAppWindow);
- assertWindowHigher(mImeWindow, mDockedDividerWindow);
assertWindowHigher(mImeWindow, mStatusBarWindow);
// And, IME dialogs should always have an higher layer than the IME.
@@ -489,77 +487,6 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testDockedDividerPosition() {
- final Task pinnedTask =
- createTask(mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
- final WindowState pinnedWindow =
- createAppWindow(pinnedTask, ACTIVITY_TYPE_STANDARD, "pinnedWindow");
-
- final Task belowTask =
- createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final WindowState belowTaskWindow =
- createAppWindow(belowTask, ACTIVITY_TYPE_STANDARD, "belowTaskWindow");
-
- final Task splitScreenTask1 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- final WindowState splitWindow1 =
- createAppWindow(splitScreenTask1, ACTIVITY_TYPE_STANDARD, "splitWindow1");
- final Task splitScreenTask2 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- final WindowState splitWindow2 =
- createAppWindow(splitScreenTask2, ACTIVITY_TYPE_STANDARD, "splitWindow2");
- splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2, true /* moveTogether */);
- splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1, true /* moveTogether */);
-
- final Task aboveTask =
- createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final WindowState aboveTaskWindow =
- createAppWindow(aboveTask, ACTIVITY_TYPE_STANDARD, "aboveTaskWindow");
-
- mDisplayContent.assignChildLayers(mTransaction);
-
- assertWindowHigher(splitWindow1, belowTaskWindow);
- assertWindowHigher(splitWindow2, belowTaskWindow);
- assertWindowHigher(mDockedDividerWindow, splitWindow1);
- assertWindowHigher(mDockedDividerWindow, splitWindow2);
- assertWindowHigher(aboveTaskWindow, mDockedDividerWindow);
- assertWindowHigher(pinnedWindow, aboveTaskWindow);
- }
-
-
- @Test
- public void testDockedDividerPosition_noAboveTask() {
- final Task pinnedTask =
- createTask(mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
- final WindowState pinnedWindow =
- createAppWindow(pinnedTask, ACTIVITY_TYPE_STANDARD, "pinnedWindow");
-
- final Task belowTask =
- createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final WindowState belowTaskWindow =
- createAppWindow(belowTask, ACTIVITY_TYPE_STANDARD, "belowTaskWindow");
-
- final Task splitScreenTask1 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- final WindowState splitWindow1 =
- createAppWindow(splitScreenTask1, ACTIVITY_TYPE_STANDARD, "splitWindow1");
- final Task splitScreenTask2 =
- createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
- final WindowState splitWindow2 =
- createAppWindow(splitScreenTask2, ACTIVITY_TYPE_STANDARD, "splitWindow2");
- splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2, true /* moveTogether */);
- splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1, true /* moveTogether */);
-
- mDisplayContent.assignChildLayers(mTransaction);
-
- assertWindowHigher(splitWindow1, belowTaskWindow);
- assertWindowHigher(splitWindow2, belowTaskWindow);
- assertWindowHigher(mDockedDividerWindow, splitWindow1);
- assertWindowHigher(mDockedDividerWindow, splitWindow2);
- assertWindowHigher(pinnedWindow, mDockedDividerWindow);
- }
-
- @Test
public void testAttachNavBarWhenEnteringRecents_expectNavBarHigherThanIme() {
// create RecentsAnimationController
IRecentsAnimationRunner mockRunner = mock(IRecentsAnimationRunner.class);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ef13cd964f6c..fb101c15c913 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -87,7 +87,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -163,13 +162,26 @@ public class UsageStatsService extends SystemService implements
private static final boolean ENABLE_KERNEL_UPDATES = true;
private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
- private static final File USAGE_STATS_LEGACY_DIR = new File(
- Environment.getDataSystemDirectory(), "usagestats");
- // For migration purposes, indicates whether to keep the legacy usage stats directory or not
- private static final boolean KEEP_LEGACY_DIR = false;
-
- private static final File COMMON_USAGE_STATS_DE_DIR =
+ // /data/system/usagestats. Now only used for globalcomponentusage. Previously per-user stats
+ // were stored here too, but they've been moved to /data/system_ce/$userId/usagestats.
+ private static final File COMMON_USAGE_STATS_DIR =
+ new File(Environment.getDataSystemDirectory(), "usagestats");
+ private static final File LEGACY_USER_USAGE_STATS_DIR = COMMON_USAGE_STATS_DIR;
+
+ // /data/system_de/usagestats. When the globalcomponentusage file was added, it was incorrectly
+ // added here instead of in /data/system/usagestats where it should be. We lazily migrate this
+ // file by reading it from here if needed, and always writing it to the new path. We don't
+ // delete the old directory, as system_server no longer has permission to do so.
+ //
+ // Note, this migration is *not* related to the migration of the per-user stats from
+ // /data/system/usagestats/$userId to /data/system_ce/$userId/usagestats mentioned above. Both
+ // of these just happen to involve /data/system/usagestats. /data/system is the right place for
+ // system data not tied to a user, but the wrong place for per-user data. So due to two
+ // separate mistakes, we've unfortunately ended up with one case where we need to move files out
+ // of /data/system, and one case where we need to move a different file *into* /data/system.
+ private static final File LEGACY_COMMON_USAGE_STATS_DIR =
new File(Environment.getDataSystemDeDirectory(), "usagestats");
+
private static final String GLOBAL_COMPONENT_USAGE_FILE_NAME = "globalcomponentusage";
private static final char TOKEN_DELIMITER = '/';
@@ -627,6 +639,10 @@ public class UsageStatsService extends SystemService implements
mAppStandby.initializeDefaultsForSystemApps(userId);
}
+ private boolean isInstantApp(String packageName, int userId) {
+ return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
+ }
+
private boolean shouldObfuscateInstantAppsForCaller(int callingUid, int userId) {
return !mPackageManagerInternal.canAccessInstantApps(callingUid, userId);
}
@@ -726,7 +742,7 @@ public class UsageStatsService extends SystemService implements
final int previousVersion = Integer.parseInt(reader.readLine());
// UsageStatsDatabase.BACKUP_VERSION was 4 when usage stats were migrated to CE.
if (previousVersion >= 4) {
- deleteLegacyDir(userId);
+ deleteLegacyUserDir(userId);
return;
}
// If migration logic needs to be changed in a future version, do it here.
@@ -747,7 +763,7 @@ public class UsageStatsService extends SystemService implements
}
Slog.i(TAG, "Starting migration to system CE for user " + userId);
- final File legacyUserDir = new File(USAGE_STATS_LEGACY_DIR, Integer.toString(userId));
+ final File legacyUserDir = new File(LEGACY_USER_USAGE_STATS_DIR, Integer.toString(userId));
if (legacyUserDir.exists()) {
copyRecursively(usageStatsDir, legacyUserDir);
}
@@ -762,8 +778,8 @@ public class UsageStatsService extends SystemService implements
}
Slog.i(TAG, "Finished migration to system CE for user " + userId);
- // Migration was successful - delete the legacy directory
- deleteLegacyDir(userId);
+ // Migration was successful - delete the legacy user directory
+ deleteLegacyUserDir(userId);
}
private static void copyRecursively(final File parent, File f) {
@@ -794,21 +810,14 @@ public class UsageStatsService extends SystemService implements
}
}
- private void deleteLegacyDir(int userId) {
- final File legacyUserDir = new File(USAGE_STATS_LEGACY_DIR, Integer.toString(userId));
- if (!KEEP_LEGACY_DIR && legacyUserDir.exists()) {
+ private void deleteLegacyUserDir(int userId) {
+ final File legacyUserDir = new File(LEGACY_USER_USAGE_STATS_DIR, Integer.toString(userId));
+ if (legacyUserDir.exists()) {
deleteRecursively(legacyUserDir);
if (legacyUserDir.exists()) {
Slog.w(TAG, "Error occurred while attempting to delete legacy usage stats "
+ "dir for user " + userId);
}
- // If all users have been migrated, delete the parent legacy usage stats directory
- if (USAGE_STATS_LEGACY_DIR.list() != null
- && USAGE_STATS_LEGACY_DIR.list().length == 0) {
- if (!USAGE_STATS_LEGACY_DIR.delete()) {
- Slog.w(TAG, "Error occurred while attempting to delete legacy usage stats dir");
- }
- }
}
}
@@ -878,11 +887,16 @@ public class UsageStatsService extends SystemService implements
return;
}
- final File usageStatsDeDir = new File(Environment.getDataSystemDeDirectory(userId),
- "usagestats");
- if (!usageStatsDeDir.mkdirs() && !usageStatsDeDir.exists()) {
- throw new IllegalStateException("Usage stats DE directory does not exist: "
- + usageStatsDeDir.getAbsolutePath());
+ final File deDir = Environment.getDataSystemDeDirectory(userId);
+ final File usageStatsDeDir = new File(deDir, "usagestats");
+ if (!usageStatsDeDir.mkdir() && !usageStatsDeDir.exists()) {
+ if (deDir.exists()) {
+ Slog.e(TAG, "Failed to create " + usageStatsDeDir);
+ } else {
+ Slog.w(TAG, "User " + userId + " was already removed! Discarding pending events");
+ pendingEvents.clear();
+ }
+ return;
}
final File pendingEventsFile = new File(usageStatsDeDir,
"pendingevents_" + System.currentTimeMillis());
@@ -903,13 +917,16 @@ public class UsageStatsService extends SystemService implements
}
private void loadGlobalComponentUsageLocked() {
- final File[] packageUsageFile = COMMON_USAGE_STATS_DE_DIR.listFiles(
- (dir, name) -> TextUtils.equals(name, GLOBAL_COMPONENT_USAGE_FILE_NAME));
- if (packageUsageFile == null || packageUsageFile.length == 0) {
- return;
+ AtomicFile af = new AtomicFile(new File(COMMON_USAGE_STATS_DIR,
+ GLOBAL_COMPONENT_USAGE_FILE_NAME));
+ if (!af.exists()) {
+ af = new AtomicFile(new File(LEGACY_COMMON_USAGE_STATS_DIR,
+ GLOBAL_COMPONENT_USAGE_FILE_NAME));
+ if (!af.exists()) {
+ return;
+ }
+ Slog.i(TAG, "Reading " + GLOBAL_COMPONENT_USAGE_FILE_NAME + " file from old location");
}
-
- final AtomicFile af = new AtomicFile(packageUsageFile[0]);
final Map<String, Long> tmpUsage = new ArrayMap<>();
try {
try (FileInputStream in = af.openRead()) {
@@ -927,7 +944,7 @@ public class UsageStatsService extends SystemService implements
}
} catch (Exception e) {
// Most likely trying to read a corrupted file - log the failure
- Slog.e(TAG, "Could not read " + packageUsageFile[0]);
+ Slog.e(TAG, "Could not read " + af.getBaseFile());
}
}
@@ -936,11 +953,11 @@ public class UsageStatsService extends SystemService implements
return;
}
- if (!COMMON_USAGE_STATS_DE_DIR.mkdirs() && !COMMON_USAGE_STATS_DE_DIR.exists()) {
- throw new IllegalStateException("Common usage stats DE directory does not exist: "
- + COMMON_USAGE_STATS_DE_DIR.getAbsolutePath());
+ if (!COMMON_USAGE_STATS_DIR.mkdirs() && !COMMON_USAGE_STATS_DIR.exists()) {
+ throw new IllegalStateException("Common usage stats directory does not exist: "
+ + COMMON_USAGE_STATS_DIR.getAbsolutePath());
}
- final File lastTimePackageFile = new File(COMMON_USAGE_STATS_DE_DIR,
+ final File lastTimePackageFile = new File(COMMON_USAGE_STATS_DIR,
GLOBAL_COMPONENT_USAGE_FILE_NAME);
final AtomicFile af = new AtomicFile(lastTimePackageFile);
FileOutputStream fos = null;
@@ -1014,8 +1031,7 @@ public class UsageStatsService extends SystemService implements
uid = 0;
}
- if (event.mPackage != null
- && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) {
+ if (event.mPackage != null && isInstantApp(event.mPackage, userId)) {
event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
}
@@ -1347,7 +1363,7 @@ public class UsageStatsService extends SystemService implements
if (obfuscateInstantApps) {
for (int i = list.size() - 1; i >= 0; i--) {
final UsageStats stats = list.get(i);
- if (mPackageManagerInternal.isPackageEphemeral(userId, stats.mPackageName)) {
+ if (isInstantApp(stats.mPackageName, userId)) {
list.set(i, stats.getObfuscatedForInstantApp());
}
}
@@ -2344,16 +2360,18 @@ public class UsageStatsService extends SystemService implements
"Don't have permission to query app standby bucket");
}
}
- if (packageUid < 0) {
+
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final boolean cannotAccessInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
+ userId);
+ if (packageUid < 0 || (isInstantApp && cannotAccessInstantApps)) {
throw new IllegalArgumentException(
"Cannot get standby bucket for non existent package (" + packageName + ")");
}
- final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
- userId);
final long token = Binder.clearCallingIdentity();
try {
return mAppStandby.getAppStandbyBucket(packageName, userId,
- SystemClock.elapsedRealtime(), obfuscateInstantApps);
+ SystemClock.elapsedRealtime(), false /* obfuscateInstantApps */);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2390,12 +2408,19 @@ public class UsageStatsService extends SystemService implements
throw new SecurityException(
"Don't have permission to query app standby bucket");
}
+ final boolean cannotAccessInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
+ userId);
final long token = Binder.clearCallingIdentity();
try {
final List<AppStandbyInfo> standbyBucketList =
mAppStandby.getAppStandbyBuckets(userId);
- return (standbyBucketList == null) ? ParceledListSlice.emptyList()
- : new ParceledListSlice<>(standbyBucketList);
+ if (standbyBucketList == null) {
+ return ParceledListSlice.emptyList();
+ }
+ final int targetUserId = userId;
+ standbyBucketList.removeIf(
+ i -> cannotAccessInstantApps && isInstantApp(i.mPackageName, targetUserId));
+ return new ParceledListSlice<>(standbyBucketList);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2435,17 +2460,18 @@ public class UsageStatsService extends SystemService implements
"Don't have permission to query min app standby bucket");
}
}
- if (packageUid < 0) {
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final boolean cannotAccessInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
+ userId);
+ if (packageUid < 0 || (isInstantApp && cannotAccessInstantApps)) {
throw new IllegalArgumentException(
"Cannot get min standby bucket for non existent package ("
+ packageName + ")");
}
- final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
- userId);
final long token = Binder.clearCallingIdentity();
try {
- return mAppStandby.getAppMinStandbyBucket(
- packageName, UserHandle.getAppId(packageUid), userId, obfuscateInstantApps);
+ return mAppStandby.getAppMinStandbyBucket(packageName,
+ UserHandle.getAppId(packageUid), userId, false /* obfuscateInstantApps */);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 42d446d058b4..c260617056ac 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -80,6 +80,7 @@ import android.service.voice.IDspHotwordDetectionCallback;
import android.service.voice.IHotwordDetectionService;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
+import android.speech.IRecognitionServiceManager;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
@@ -529,6 +530,7 @@ final class HotwordDetectionConnection {
mValidatingDspTrigger = false;
try {
enforcePermissionsForDataDelivery();
+ enforceExtraKeyphraseIdNotLeaked(result, recognitionEvent);
} catch (SecurityException e) {
externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
return;
@@ -605,6 +607,7 @@ final class HotwordDetectionConnection {
mValidatingDspTrigger = false;
try {
enforcePermissionsForDataDelivery();
+ enforceExtraKeyphraseIdNotLeaked(result, recognitionEvent);
} catch (SecurityException e) {
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
mDetectorType,
@@ -966,6 +969,7 @@ final class HotwordDetectionConnection {
updateAudioFlinger(connection, mAudioFlinger);
updateContentCaptureManager(connection);
+ updateSpeechService(connection);
updateServiceIdentity(connection);
return connection;
}
@@ -1103,6 +1107,14 @@ final class HotwordDetectionConnection {
new ContentCaptureOptions(null)));
}
+ private static void updateSpeechService(ServiceConnection connection) {
+ IBinder b = ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE);
+ IRecognitionServiceManager binderService = IRecognitionServiceManager.Stub.asInterface(b);
+ connection.run(service -> {
+ service.updateRecognitionServiceManager(binderService);
+ });
+ }
+
private void updateServiceIdentity(ServiceConnection connection) {
connection.run(service -> service.ping(new IRemoteCallback.Stub() {
@Override
@@ -1194,6 +1206,19 @@ final class HotwordDetectionConnection {
}
}
+ private static void enforceExtraKeyphraseIdNotLeaked(HotwordDetectedResult result,
+ SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
+ // verify the phrase ID in HotwordDetectedResult is not exposing extra phrases
+ // the DSP did not detect
+ for (SoundTrigger.KeyphraseRecognitionExtra keyphrase : recognitionEvent.keyphraseExtras) {
+ if (keyphrase.getKeyphraseId() == result.getHotwordPhraseId()) {
+ return;
+ }
+ }
+ throw new SecurityException("Ignoring #onDetected due to trusted service "
+ + "sharing a keyphrase ID which the DSP did not detect");
+ }
+
private static final String OP_MESSAGE =
"Providing hotword detection result to VoiceInteractionService";
};
diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java
index 1342038c6477..a74c0bb99549 100644
--- a/telecomm/java/android/telecom/Logging/EventManager.java
+++ b/telecomm/java/android/telecom/Logging/EventManager.java
@@ -180,7 +180,7 @@ public class EventManager {
}
}
- private final List<Event> mEvents = Collections.synchronizedList(new LinkedList<>());
+ private final List<Event> mEvents = Collections.synchronizedList(new ArrayList<>());
private final Loggable mRecordEntry;
public EventRecord(Loggable recordEntry) {
@@ -197,7 +197,7 @@ public class EventManager {
}
public List<Event> getEvents() {
- return new LinkedList<>(mEvents);
+ return new ArrayList<>(mEvents);
}
public List<EventTiming> extractEventTimings() {
@@ -205,7 +205,7 @@ public class EventManager {
return Collections.emptyList();
}
- LinkedList<EventTiming> result = new LinkedList<>();
+ ArrayList<EventTiming> result = new ArrayList<>();
Map<String, PendingResponse> pendingResponses = new HashMap<>();
synchronized (mEvents) {
for (Event event : mEvents) {
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index b8ad9e2fbe6c..ff87ab00ae8b 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -359,7 +359,7 @@ public class ParcelableCallAnalytics implements Parcelable {
eventTimings = new ArrayList<>();
in.readTypedList(eventTimings, EventTiming.CREATOR);
isVideoCall = readByteAsBoolean(in);
- videoEvents = new LinkedList<>();
+ videoEvents = new ArrayList<>();
in.readTypedList(videoEvents, VideoEvent.CREATOR);
callSource = in.readInt();
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e0f5b2095190..0f7dde5a18d9 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1179,7 +1179,7 @@ public class TelecomManager {
if (service != null) {
try {
return service.getSimCallManager(
- SubscriptionManager.getDefaultSubscriptionId());
+ SubscriptionManager.getDefaultSubscriptionId(), mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSimCallManager");
}
@@ -1201,7 +1201,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getSimCallManager(subscriptionId);
+ return service.getSimCallManager(subscriptionId, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSimCallManager");
}
@@ -1225,7 +1225,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getSimCallManagerForUser(userId);
+ return service.getSimCallManagerForUser(userId, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSimCallManagerForUser");
}
@@ -1500,7 +1500,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- service.registerPhoneAccount(account);
+ service.registerPhoneAccount(account, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#registerPhoneAccount", e);
}
@@ -1516,7 +1516,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- service.unregisterPhoneAccount(accountHandle);
+ service.unregisterPhoneAccount(accountHandle, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#unregisterPhoneAccount", e);
}
@@ -1597,7 +1597,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getDefaultDialerPackage();
+ return service.getDefaultDialerPackage(mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get the default dialer package name.", e);
}
@@ -1671,7 +1671,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getSystemDialerPackage();
+ return service.getSystemDialerPackage(mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get the system dialer package name.", e);
}
@@ -2076,7 +2076,8 @@ public class TelecomManager {
"acceptHandover for API > O-MR1");
return;
}
- service.addNewIncomingCall(phoneAccount, extras == null ? new Bundle() : extras);
+ service.addNewIncomingCall(phoneAccount, extras == null ? new Bundle() : extras,
+ mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
}
@@ -2118,7 +2119,8 @@ public class TelecomManager {
if (service != null) {
try {
service.addNewIncomingConference(
- phoneAccount, extras == null ? new Bundle() : extras);
+ phoneAccount, extras == null ? new Bundle() : extras,
+ mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming conference: " + phoneAccount, e);
}
@@ -2414,7 +2416,7 @@ public class TelecomManager {
Intent result = null;
if (service != null) {
try {
- result = service.createManageBlockedNumbersIntent();
+ result = service.createManageBlockedNumbersIntent(mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
}
@@ -2571,7 +2573,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- service.acceptHandover(srcAddr, videoState, destAcct);
+ service.acceptHandover(srcAddr, videoState, destAcct, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "RemoteException acceptHandover: " + e);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 37403a806daf..101280abce85 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -106,22 +106,22 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#getSimCallManager
*/
- PhoneAccountHandle getSimCallManager(int subId);
+ PhoneAccountHandle getSimCallManager(int subId, String callingPackage);
/**
* @see TelecomServiceImpl#getSimCallManagerForUser
*/
- PhoneAccountHandle getSimCallManagerForUser(int userId);
+ PhoneAccountHandle getSimCallManagerForUser(int userId, String callingPackage);
/**
* @see TelecomServiceImpl#registerPhoneAccount
*/
- void registerPhoneAccount(in PhoneAccount metadata);
+ void registerPhoneAccount(in PhoneAccount metadata, String callingPackage);
/**
* @see TelecomServiceImpl#unregisterPhoneAccount
*/
- void unregisterPhoneAccount(in PhoneAccountHandle account);
+ void unregisterPhoneAccount(in PhoneAccountHandle account, String callingPackage);
/**
* @see TelecomServiceImpl#clearAccounts
@@ -154,7 +154,7 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#getDefaultDialerPackage
*/
- String getDefaultDialerPackage();
+ String getDefaultDialerPackage(String callingPackage);
/**
* @see TelecomServiceImpl#getDefaultDialerPackage
@@ -164,7 +164,7 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#getSystemDialerPackage
*/
- String getSystemDialerPackage();
+ String getSystemDialerPackage(String callingPackage);
/**
* @see TelecomServiceImpl#dumpCallAnalytics
@@ -262,12 +262,15 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#addNewIncomingCall
*/
- void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
+ void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras,
+ String callingPackage);
/**
* @see TelecomServiceImpl#addNewIncomingConference
*/
- void addNewIncomingConference(in PhoneAccountHandle phoneAccount, in Bundle extras);
+ void addNewIncomingConference(in PhoneAccountHandle phoneAccount, in Bundle extras,
+ String callingPackage);
+
/**
* @see TelecomServiceImpl#addNewUnknownCall
@@ -303,7 +306,7 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#createManageBlockedNumbersIntent
**/
- Intent createManageBlockedNumbersIntent();
+ Intent createManageBlockedNumbersIntent(String callingPackage);
/**
* @see TelecomServiceImpl#createLaunchEmergencyDialerIntent
@@ -330,7 +333,8 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#acceptHandover
*/
- void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
+ void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct,
+ String callingPackage);
/**
* @see TelecomServiceImpl#setTestEmergencyPhoneAccountPackageNameFilter
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 8c78f74b2e59..de70dcb9b29c 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -186,6 +186,7 @@ public final class TelephonyUtils {
case TelephonyManager.DATA_CONNECTED: return "CONNECTED";
case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED";
case TelephonyManager.DATA_DISCONNECTING: return "DISCONNECTING";
+ case TelephonyManager.DATA_HANDOVER_IN_PROGRESS: return "HANDOVERINPROGRESS";
case TelephonyManager.DATA_UNKNOWN: return "UNKNOWN";
}
// This is the error case. The well-defined value for UNKNOWN is -1.
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index ac1f376cf6b5..e882b259f45e 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -125,6 +125,12 @@ public final class DataFailCause {
public static final int UNSUPPORTED_QCI_VALUE = 0x3B;
/** Procedure requested by the UE was rejected because the bearer handling is not supported. */
public static final int BEARER_HANDLING_NOT_SUPPORTED = 0x3C;
+ /**
+ * This cause is used to report a service or option not available event only when no other
+ * cause in the service or option not available class applies.
+ * @hide // TODO: Unhide in U.
+ */
+ public static final int SERVICE_OR_OPTION_NOT_AVAILABLE = 0x3F;
/** Max number of Packet Data Protocol (PDP) context reached. */
public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 0x41;
/** Unsupported APN in current public land mobile network (PLMN). */
@@ -1135,6 +1141,7 @@ public final class DataFailCause {
sFailCauseMap.put(ONLY_NON_IP_ALLOWED, "ONLY_NON_IP_ALLOWED");
sFailCauseMap.put(UNSUPPORTED_QCI_VALUE, "UNSUPPORTED_QCI_VALUE");
sFailCauseMap.put(BEARER_HANDLING_NOT_SUPPORTED, "BEARER_HANDLING_NOT_SUPPORTED");
+ sFailCauseMap.put(SERVICE_OR_OPTION_NOT_AVAILABLE, "SERVICE_OR_OPTION_NOT_AVAILABLE");
sFailCauseMap.put(ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
"ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED");
sFailCauseMap.put(UNSUPPORTED_APN_IN_CURRENT_PLMN,
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c701e443a426..1d6798b7fc6e 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -183,8 +183,17 @@ public final class NetworkRegistrationInfo implements Parcelable {
@TransportType
private final int mTransportType;
+ /**
+ * The initial registration state
+ */
+ @RegistrationState
+ private final int mInitialRegistrationState;
+
+ /**
+ * The registration state that might have been overridden by config
+ */
@RegistrationState
- private final int mRegistrationState;
+ private int mRegistrationState;
/**
* Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
@@ -255,6 +264,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
mDomain = domain;
mTransportType = transportType;
mRegistrationState = registrationState;
+ mInitialRegistrationState = registrationState;
mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
setAccessNetworkTechnology(accessNetworkTechnology);
@@ -310,6 +320,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
mDomain = source.readInt();
mTransportType = source.readInt();
mRegistrationState = source.readInt();
+ mInitialRegistrationState = source.readInt();
mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
@@ -336,6 +347,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
mDomain = nri.mDomain;
mTransportType = nri.mTransportType;
mRegistrationState = nri.mRegistrationState;
+ mInitialRegistrationState = nri.mInitialRegistrationState;
mRoamingType = nri.mRoamingType;
mAccessNetworkTechnology = nri.mAccessNetworkTechnology;
mIsUsingCarrierAggregation = nri.mIsUsingCarrierAggregation;
@@ -398,6 +410,15 @@ public final class NetworkRegistrationInfo implements Parcelable {
}
/**
+ * @return The initial registration state.
+ *
+ * @hide
+ */
+ public @RegistrationState int getInitialRegistrationState() {
+ return mInitialRegistrationState;
+ }
+
+ /**
* @return {@code true} if registered on roaming or home network, {@code false} otherwise.
*/
public boolean isRegistered() {
@@ -451,6 +472,17 @@ public final class NetworkRegistrationInfo implements Parcelable {
*/
public void setRoamingType(@ServiceState.RoamingType int roamingType) {
mRoamingType = roamingType;
+
+ // make sure mRegistrationState to be consistent in case of any roaming type override
+ if (isRoaming()) {
+ if (mRegistrationState == REGISTRATION_STATE_HOME) {
+ mRegistrationState = REGISTRATION_STATE_ROAMING;
+ }
+ } else {
+ if (mRegistrationState == REGISTRATION_STATE_ROAMING) {
+ mRegistrationState = REGISTRATION_STATE_HOME;
+ }
+ }
}
/**
@@ -634,6 +666,8 @@ public final class NetworkRegistrationInfo implements Parcelable {
.append(" transportType=").append(
AccessNetworkConstants.transportTypeToString(mTransportType))
.append(" registrationState=").append(registrationStateToString(mRegistrationState))
+ .append(" mInitialRegistrationState=")
+ .append(registrationStateToString(mInitialRegistrationState))
.append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
@@ -654,10 +688,10 @@ public final class NetworkRegistrationInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
- mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn,
- mIsUsingCarrierAggregation);
+ return Objects.hash(mDomain, mTransportType, mRegistrationState, mInitialRegistrationState,
+ mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly,
+ mAvailableServices, mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState,
+ mRplmn, mIsUsingCarrierAggregation);
}
@Override
@@ -672,6 +706,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegistrationState == other.mRegistrationState
+ && mInitialRegistrationState == other.mInitialRegistrationState
&& mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
@@ -694,6 +729,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegistrationState);
+ dest.writeInt(mInitialRegistrationState);
dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
@@ -790,7 +826,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
private int mTransportType;
@RegistrationState
- private int mRegistrationState;
+ private int mInitialRegistrationState;
@NetworkType
private int mAccessNetworkTechnology;
@@ -851,7 +887,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
* @return The same instance of the builder.
*/
public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) {
- mRegistrationState = registrationState;
+ mInitialRegistrationState = registrationState;
return this;
}
@@ -970,7 +1006,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
*/
@SystemApi
public @NonNull NetworkRegistrationInfo build() {
- return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
+ return new NetworkRegistrationInfo(mDomain, mTransportType, mInitialRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
mDataSpecificRegistrationInfo);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2337a5aae467..1afb5a38014d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -483,6 +483,14 @@ public class SubscriptionManager {
public static final String SUBSCRIPTION_TYPE = SimInfo.COLUMN_SUBSCRIPTION_TYPE;
/**
+ * TelephonyProvider column name for last used TP - message Reference
+ * <P>Type: INTEGER (int)</P> with -1 as default value
+ * TP - Message Reference valid range [0 - 255]
+ * @hide
+ */
+ public static final String TP_MESSAGE_REF = SimInfo.COLUMN_TP_MESSAGE_REF;
+
+ /**
* TelephonyProvider column name data_enabled_override_rules.
* It's a list of rules for overriding data enabled settings. The syntax is
* For example, "mms=nonDefault" indicates enabling data for mms in non-default subscription.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b6f86527b747..d1729f886f6e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7744,7 +7744,7 @@ public class TelephonyManager {
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* TODO: remove this one. use {@link #rebootModem()} for reset type 1 and
- * {@link #resetRadioConfig()} for reset type 3
+ * {@link #resetRadioConfig()} for reset type 3 (b/116476729)
*
* @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
* @return true on success; false on any failure.
@@ -8244,6 +8244,30 @@ public class TelephonyManager {
public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
/** Authentication type for UICC challenge is EAP AKA. See RFC 4187 for details. */
public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
+ /**
+ * Authentication type for GBA Bootstrap Challenge is GBA_BOOTSTRAP.
+ * See 3GPP 33.220 Section 5.3.2.
+ * @hide
+ */
+ public static final int AUTHTYPE_GBA_BOOTSTRAP = PhoneConstants.AUTH_CONTEXT_GBA_BOOTSTRAP;
+ /**
+ * Authentication type for GBA Network Application Functions (NAF) key
+ * External Challenge is AUTHTYPE_GBA_NAF_KEY_EXTERNAL.
+ * See 3GPP 33.220 Section 5.3.2.
+ * @hide
+ */
+ public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL =
+ PhoneConstants.AUTHTYPE_GBA_NAF_KEY_EXTERNAL;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ AUTHTYPE_EAP_SIM,
+ AUTHTYPE_EAP_AKA,
+ AUTHTYPE_GBA_BOOTSTRAP,
+ AUTHTYPE_GBA_NAF_KEY_EXTERNAL
+ })
+ public @interface AuthType {}
/**
* Returns the response of authentication for the default subscription.
@@ -8258,7 +8282,7 @@ public class TelephonyManager {
* </ul>
*
* @param appType the icc application type, like {@link #APPTYPE_USIM}
- * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or
* {@link #AUTHTYPE_EAP_SIM}
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
@@ -8273,7 +8297,7 @@ public class TelephonyManager {
// READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
// it's not public API.
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
- public String getIccAuthentication(int appType, int authType, String data) {
+ public String getIccAuthentication(int appType,@AuthType int authType, String data) {
return getIccAuthentication(getSubId(), appType, authType, data);
}
@@ -8286,7 +8310,7 @@ public class TelephonyManager {
*
* @param subId subscription ID used for authentication
* @param appType the icc application type, like {@link #APPTYPE_USIM}
- * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or
* {@link #AUTHTYPE_EAP_SIM}
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
@@ -8300,7 +8324,7 @@ public class TelephonyManager {
* @hide
*/
@UnsupportedAppUsage
- public String getIccAuthentication(int subId, int appType, int authType, String data) {
+ public String getIccAuthentication(int subId, int appType,@AuthType int authType, String data) {
try {
IPhoneSubInfo info = getSubscriberInfoService();
if (info == null)
@@ -16209,7 +16233,8 @@ public class TelephonyManager {
* may encounter an {@link IllegalStateException} when trying to register more callbacks.
*
* @param executor The executor of where the callback will execute.
- * @param callback The {@link TelephonyCallback} object to register.
+ * @param callback The {@link TelephonyCallback} object to register. The caller should hold a
+ * reference to the callback. The framework only holds a weak reference.
*/
public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull TelephonyCallback callback) {
@@ -16304,7 +16329,8 @@ public class TelephonyManager {
* @param includeLocationData Specifies if the caller would like to receive
* location related information.
* @param executor The executor of where the callback will execute.
- * @param callback The {@link TelephonyCallback} object to register.
+ * @param callback The {@link TelephonyCallback} object to register. The caller should hold a
+ * reference to the callback. The framework only holds a weak reference.
*/
public void registerTelephonyCallback(@IncludeLocationData int includeLocationData,
@NonNull @CallbackExecutor Executor executor,
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a673807a3f97..1252dc178cb9 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -769,7 +769,7 @@ public class EuiccManager {
public static final int ERROR_INSTALL_PROFILE = 10009;
/**
- * Failed to load profile onto eUICC due to Profile Poicly Rules.
+ * Failed to load profile onto eUICC due to Profile Policy Rules.
* @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
*/
public static final int ERROR_DISALLOWED_BY_PPR = 10010;
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 5bae1ad72d93..f8048aa3731c 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -539,7 +539,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -601,7 +600,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -649,7 +647,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -862,7 +859,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -937,7 +933,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -1111,7 +1106,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -1226,7 +1220,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
@@ -1415,7 +1408,6 @@ public class ImsMmTelManager implements RegistrationManager {
* <li>The caller has carrier privileges (see
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
* active subscription.</li>
- * <li>The caller is the default SMS app for the device.</li>
* </ul>
* <p>The profile owner is an app that owns a managed profile on the device; for more details
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index e00ea0ea4d5e..4439e5c35d83 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -540,6 +540,8 @@ public class ImsRcsManager {
try {
return imsRcsController.isCapable(mSubId, capability, radioTech);
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException e) {
Log.w(TAG, "Error calling IImsRcsController#isCapable", e);
throw new ImsException("Remote IMS Service is not available",
@@ -577,6 +579,8 @@ public class ImsRcsManager {
try {
return imsRcsController.isAvailable(mSubId, capability, radioTech);
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException e) {
Log.w(TAG, "Error calling IImsRcsController#isAvailable", e);
throw new ImsException("Remote IMS Service is not available",
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index be233b82c426..50fcdf86be79 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -52,6 +52,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@@ -188,6 +189,7 @@ public class ImsService extends Service {
new SparseArray<>();
private IImsServiceControllerListener mListener;
+ private final Object mListenerLock = new Object();
private Executor mExecutor;
/**
@@ -225,7 +227,30 @@ public class ImsService extends Service {
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
@Override
public void setListener(IImsServiceControllerListener l) {
- mListener = l;
+ synchronized (mListenerLock) {
+ if (mListener != null && mListener.asBinder().isBinderAlive()) {
+ try {
+ mListener.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(LOG_TAG, "IImsServiceControllerListener does not exist");
+ }
+ }
+
+ mListener = l;
+ if (mListener == null) {
+ executeMethodAsync(() -> releaseResource(), "releaseResource");
+ return;
+ }
+
+ try {
+ mListener.asBinder().linkToDeath(mDeathRecipient, 0);
+ Log.i(LOG_TAG, "setListener: register linkToDeath");
+ } catch (RemoteException e) {
+ // RemoteException means target binder process was crashed
+ // release resource
+ executeMethodAsync(() -> releaseResource(), "releaseResource");
+ }
+ }
}
@Override
@@ -364,28 +389,15 @@ public class ImsService extends Service {
ImsService.this.disableImsForSubscription(slotId, subId), "disableIms");
}
- // Call the methods with a clean calling identity on the executor and wait indefinitely for
- // the future to return.
- private void executeMethodAsync(Runnable r, String errorLogName) {
- try {
- CompletableFuture.runAsync(
- () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
- } catch (CancellationException | CompletionException e) {
- Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
- + e.getMessage());
- }
- }
- private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) {
- CompletableFuture<T> future = CompletableFuture.supplyAsync(
- () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
- try {
- return future.get();
- } catch (ExecutionException | InterruptedException e) {
- Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
- + e.getMessage());
- return null;
- }
+ };
+
+ private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.w(LOG_TAG,
+ "IImsServiceControllerListener binder to framework has died. Cleaning up");
+ executeMethodAsync(() -> releaseResource(), "releaseResource");
}
};
@@ -490,6 +502,9 @@ public class ImsService extends Service {
}
private void removeImsFeature(int slotId, int featureType) {
+ // clear cached data
+ notifySubscriptionRemoved(slotId);
+
synchronized (mFeaturesBySlot) {
// get ImsFeature associated with the slot/feature
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
@@ -507,7 +522,6 @@ public class ImsService extends Service {
f.onFeatureRemoved();
features.remove(featureType);
}
-
}
/**
@@ -552,6 +566,54 @@ public class ImsService extends Service {
return createFlag;
}
+ private void releaseResource() {
+ Log.w(LOG_TAG, "cleaning up features");
+ synchronized (mFeaturesBySlot) {
+ SparseArray<ImsFeature> features;
+ ImsFeature imsFeature;
+
+ for (int i = 0; i < mFeaturesBySlot.size(); i++) {
+ features = mFeaturesBySlot.valueAt(i);
+ if (features == null) {
+ continue;
+ }
+
+ for (int index = 0; index < features.size(); index++) {
+ imsFeature = features.valueAt(index);
+ if (imsFeature != null) {
+ imsFeature.onFeatureRemoved();
+ }
+ }
+ features.clear();
+ }
+ mFeaturesBySlot.clear();
+ }
+ }
+
+ // Call the methods with a clean calling identity on the executor and wait indefinitely for
+ // the future to return.
+ private void executeMethodAsync(Runnable r, String errorLogName) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ return null;
+ }
+ }
+
/**
* When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService}
* currently supports. This will trigger the framework to set up the {@link ImsFeature}s that
@@ -574,10 +636,14 @@ public class ImsService extends Service {
*/
public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)
throws RemoteException {
- if (mListener == null) {
- throw new IllegalStateException("Framework is not ready");
+ IImsServiceControllerListener l;
+ synchronized (mListenerLock) {
+ if (mListener == null) {
+ throw new IllegalStateException("Framework is not ready");
+ }
+ l = mListener;
}
- mListener.onUpdateSupportedImsFeatures(c);
+ l.onUpdateSupportedImsFeatures(c);
}
/**
@@ -629,6 +695,24 @@ public class ImsService extends Service {
}
/**
+ * The subscription has removed. The ImsService should notify ImsRegistrationImplBase and
+ * ImsConfigImplBase the SIM state was changed.
+ * @param slotId The slot ID which has removed.
+ */
+ private void notifySubscriptionRemoved(int slotId) {
+ ImsRegistrationImplBase registrationImplBase =
+ getRegistration(slotId);
+ if (registrationImplBase != null) {
+ registrationImplBase.clearRegistrationCache();
+ }
+
+ ImsConfigImplBase imsConfigImplBase = getConfig(slotId);
+ if (imsConfigImplBase != null) {
+ imsConfigImplBase.clearConfigurationCache();
+ }
+ }
+
+ /**
* The framework has enabled IMS for the slot specified, the ImsService should register for IMS
* and perform all appropriate initialization to bring up all ImsFeatures.
* @deprecated Use {@link #enableImsForSubscription} instead.
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index f65b7c2a4ca7..ddd7dec8de35 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -54,6 +54,9 @@ import java.util.concurrent.Executor;
* IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
* applications and may vary. It is up to the carrier and OEM applications to ensure that the
* correct provisioning keys are being used when integrating with a vendor's ImsService.
+ *
+ * Use {@link android.telephony.ims.ImsManager#getProvisioningManager(int)} to get an instance of
+ * this manager.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
public class ProvisioningManager {
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index f371ec3a28a7..897b57f48dad 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -481,6 +481,17 @@ public class ImsConfigImplBase {
}
}
+ /**
+ * Clear cached configuration value.
+ */
+ public void clearCachedValue() {
+ Log.i(TAG, "clearCachedValue");
+ synchronized (mLock) {
+ mProvisionedIntValue.clear();
+ mProvisionedStringValue.clear();
+ }
+ }
+
// Call the methods with a clean calling identity on the executor and wait indefinitely for
// the future to return.
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
@@ -538,6 +549,7 @@ public class ImsConfigImplBase {
private final RemoteCallbackListExt<IRcsConfigCallback> mRcsCallbacks =
new RemoteCallbackListExt<>();
private byte[] mRcsConfigData;
+ private final Object mRcsConfigDataLock = new Object();
ImsConfigStub mImsConfigStub;
/**
@@ -616,12 +628,20 @@ public class ImsConfigImplBase {
private void addRcsConfigCallback(IRcsConfigCallback c) {
mRcsCallbacks.register(c);
- if (mRcsConfigData != null) {
- try {
- c.onConfigurationChanged(mRcsConfigData);
- } catch (RemoteException e) {
- Log.w(TAG, "dead binder to call onConfigurationChanged, skipping.");
+
+ // This is used to avoid calling the binder out of the synchronized scope.
+ byte[] cloneRcsConfigData;
+ synchronized (mRcsConfigDataLock) {
+ if (mRcsConfigData == null) {
+ return;
}
+ cloneRcsConfigData = mRcsConfigData.clone();
+ }
+
+ try {
+ c.onConfigurationChanged(cloneRcsConfigData);
+ } catch (RemoteException e) {
+ Log.w(TAG, "dead binder to call onConfigurationChanged, skipping.");
}
}
@@ -631,18 +651,23 @@ public class ImsConfigImplBase {
private void onNotifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) {
// cache uncompressed config
- config = isCompressed ? RcsConfig.decompressGzip(config) : config;
- if (Arrays.equals(mRcsConfigData, config)) {
- return;
+ final byte[] rcsConfigData = isCompressed ? RcsConfig.decompressGzip(config) : config;
+
+ synchronized (mRcsConfigDataLock) {
+ if (Arrays.equals(mRcsConfigData, config)) {
+ return;
+ }
+ mRcsConfigData = rcsConfigData;
}
- mRcsConfigData = config;
// can be null in testing
if (mRcsCallbacks != null) {
synchronized (mRcsCallbacks) {
mRcsCallbacks.broadcastAction(c -> {
try {
- c.onConfigurationChanged(mRcsConfigData);
+ // config is cloned here so modifications to the config passed to the
+ // vendor do not accidentally modify the cache.
+ c.onConfigurationChanged(rcsConfigData.clone());
} catch (RemoteException e) {
Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping.");
}
@@ -653,7 +678,9 @@ public class ImsConfigImplBase {
}
private void onNotifyRcsAutoConfigurationRemoved() {
- mRcsConfigData = null;
+ synchronized (mRcsConfigDataLock) {
+ mRcsConfigData = null;
+ }
if (mRcsCallbacks != null) {
synchronized (mRcsCallbacks) {
mRcsCallbacks.broadcastAction(c -> {
@@ -857,4 +884,17 @@ public class ImsConfigImplBase {
mImsConfigStub.mExecutor = executor;
}
}
+
+ /**
+ * Clear all cached config data. This will be called when the config data is no longer valid
+ * such as when the SIM was removed.
+ * @hide
+ */
+ public final void clearConfigurationCache() {
+ mImsConfigStub.clearCachedValue();
+
+ synchronized (mRcsConfigDataLock) {
+ mRcsConfigData = null;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 593f0807ef27..6fc1cc828a2c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -517,4 +517,16 @@ public class ImsRegistrationImplBase {
mExecutor = executor;
}
}
+
+ /**
+ * Clear the cached data when the subscription is no longer valid
+ * such as when a sim is removed.
+ * @hide
+ */
+ public final void clearRegistrationCache() {
+ synchronized (mLock) {
+ mUris = null;
+ mUrisSet = false;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 813e80e6f355..b2f7be677458 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -226,6 +226,8 @@ public class PhoneConstants {
// per 3GPP TS 31.102 (Section 7.1.2)
public static final int AUTH_CONTEXT_EAP_SIM = 128;
public static final int AUTH_CONTEXT_EAP_AKA = 129;
+ public static final int AUTH_CONTEXT_GBA_BOOTSTRAP = 132;
+ public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL = 133;
public static final int AUTH_CONTEXT_UNDEFINED = -1;
/**
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index b51e8d3d3c5d..7a5bf067f05f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -249,7 +249,6 @@ public class SmsMessage extends SmsMessageBase {
ENCODING_UNKNOWN, 0, 0);
}
-
/**
* Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
*
@@ -272,7 +271,7 @@ public class SmsMessage extends SmsMessageBase {
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- header, encoding, languageTable, languageShiftTable, -1);
+ header, encoding, languageTable, languageShiftTable, -1, 0);
}
/**
@@ -297,6 +296,32 @@ public class SmsMessage extends SmsMessageBase {
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable, int validityPeriod) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
+ encoding, languageTable, languageShiftTable, validityPeriod, 0);
+ }
+
+ /**
+ * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param header a byte array containing the data for the User Data Header.
+ * @param encoding encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param languageTable
+ * @param languageShiftTable
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @param messageRef TP Message Reference number
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, byte[] header, int encoding,
+ int languageTable, int languageShiftTable, int validityPeriod, int messageRef) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
@@ -350,7 +375,7 @@ public class SmsMessage extends SmsMessageBase {
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
- statusReportRequested, ret);
+ statusReportRequested, ret, messageRef);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage correctness check.
@@ -496,7 +521,7 @@ public class SmsMessage extends SmsMessageBase {
String destinationAddress, String message,
boolean statusReportRequested, int validityPeriod) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- null, ENCODING_UNKNOWN, 0, 0, validityPeriod);
+ null, ENCODING_UNKNOWN, 0, 0, validityPeriod, 0);
}
/**
@@ -507,12 +532,13 @@ public class SmsMessage extends SmsMessageBase {
* @param destinationPort the port to deliver the message to at the destination.
* @param data the data for the message.
* @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param messageRef TP Message Reference number
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, int destinationPort, byte[] data,
- boolean statusReportRequested) {
+ boolean statusReportRequested, int messageRef) {
SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
portAddrs.destPort = destinationPort;
@@ -533,7 +559,7 @@ public class SmsMessage extends SmsMessageBase {
SubmitPdu ret = new SubmitPdu();
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
- statusReportRequested, ret);
+ statusReportRequested, ret, messageRef);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage correctness check.
if (bo == null) return ret;
@@ -559,6 +585,24 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param destinationPort the port to deliver the message to at the destination.
+ * @param data the data for the message.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, int destinationPort, byte[] data,
+ boolean statusReportRequested) {
+ return getSubmitPdu(scAddress, destinationAddress, destinationPort, data,
+ statusReportRequested, 0);
+ }
+
+ /**
* Creates the beginning of a SUBMIT PDU.
*
* This is the part of the SUBMIT PDU that is common to the two versions of
@@ -576,6 +620,28 @@ public class SmsMessage extends SmsMessageBase {
private static ByteArrayOutputStream getSubmitPduHead(
String scAddress, String destinationAddress, byte mtiByte,
boolean statusReportRequested, SubmitPdu ret) {
+ return getSubmitPduHead(scAddress, destinationAddress, mtiByte, statusReportRequested, ret,
+ 0);
+ }
+
+ /**
+ * Creates the beginning of a SUBMIT PDU.
+ *
+ * This is the part of the SUBMIT PDU that is common to the two versions of
+ * {@link #getSubmitPdu}, one of which takes a byte array and the other of which takes a
+ * <code>String</code>.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param mtiByte
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param ret <code>SubmitPdu</code>.
+ * @param messageRef TP Message Reference number
+ * @return a byte array of the beginning of a SUBMIT PDU. Null for invalid destinationAddress.
+ */
+ private static ByteArrayOutputStream getSubmitPduHead(
+ String scAddress, String destinationAddress, byte mtiByte,
+ boolean statusReportRequested, SubmitPdu ret, int messageRef) {
ByteArrayOutputStream bo = new ByteArrayOutputStream(
MAX_USER_DATA_BYTES + 40);
@@ -596,7 +662,7 @@ public class SmsMessage extends SmsMessageBase {
bo.write(mtiByte);
// space for TP-Message-Reference
- bo.write(0);
+ bo.write(messageRef);
byte[] daBytes;
diff --git a/test-base/api/TEST_MAPPING b/test-base/api/TEST_MAPPING
index 86e8f766dd43..ba753f0769e4 100644
--- a/test-base/api/TEST_MAPPING
+++ b/test-base/api/TEST_MAPPING
@@ -1,7 +1,7 @@
{
"presubmit": [
{
- "name": "CtsAndroidTestBase28ApiSignatureTestCases"
+ "name": "CtsAndroidTestBase29ApiSignatureTestCases"
}
]
}
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 55704eda905e..3c8e1ed99604 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -35,6 +35,8 @@
<option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" />
</target_preparer>
+ <!-- Skip on HWASan. TODO(b/232288278): Re-enable -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="ApkVerityTest.jar" />
</test>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index 78aea1f1fb17..933a3a0458ee 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -23,16 +23,16 @@ import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
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.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarLayerPositionEnd
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
@@ -43,7 +43,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window layer will become visible when switching from the fixed orientation activity.
+ * Test IME window layer will become visible when switching from the fixed orientation activity
+ * (e.g. Launcher activity).
* To run this test: `atest FlickerTests:OpenImeWindowFromFixedOrientationAppTest`
*/
@RequiresDevice
@@ -53,24 +54,31 @@ import org.junit.runners.Parameterized
@Group2
class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val fixedOrientationApp = FixedOrientationAppHelper(instrumentation)
private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+ private val taplInstrumentation = LauncherInstrumentation()
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ // Launch the activity with expecting IME will be shown.
+ imeTestApp.launchViaIntent(wmHelper)
+ }
eachRun {
- fixedOrientationApp.launchViaIntent(wmHelper)
- this.setRotation(Surface.ROTATION_90)
+ // Swiping out the IME activity to home.
+ taplInstrumentation.goHome()
+ wmHelper.waitForHomeActivityVisible()
}
}
transitions {
+ // Bring the exist IME activity to the front in landscape mode device rotation.
+ setRotation(Surface.ROTATION_90)
imeTestApp.launchViaIntent(wmHelper)
}
teardown {
test {
- fixedOrientationApp.exit(wmHelper)
+ imeTestApp.exit(wmHelper)
}
}
}
@@ -90,7 +98,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
@FlakyTest(bugId = 206753786)
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@@ -112,7 +120,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 3,
- supportedRotations = listOf(Surface.ROTATION_0),
+ supportedRotations = listOf(Surface.ROTATION_90),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 43aa4b151548..3e2130dc480f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -45,6 +45,7 @@
android:theme="@style/CutoutShortEdges"
android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
android:windowSoftInputMode="stateVisible"
+ android:configChanges="orientation|screenSize"
android:label="ImeAppAutoFocus"
android:exported="true">
<intent-filter>
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
index bf8bd14645a0..8b69db707d41 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -16,15 +16,21 @@
package com.google.android.test.handwritingime;
import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.graphics.RectF;
import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
-import android.widget.TextView;
+import android.widget.Spinner;
import android.widget.Toast;
import java.util.Random;
@@ -33,10 +39,21 @@ public class HandwritingIme extends InputMethodService {
public static final int HEIGHT_DP = 100;
+
+ private static final int OP_NONE = 0;
+ private static final int OP_SELECT = 1;
+ private static final int OP_DELETE = 2;
+ private static final int OP_DELETE_SPACE = 3;
+ private static final int OP_INSERT = 4;
+
private Window mInkWindow;
private InkView mInk;
static final String TAG = "HandwritingIme";
+ private int mRichGestureMode = OP_NONE;
+ private Spinner mRichGestureModeSpinner;
+ private PointF mRichGestureStartPoint;
+
interface HandwritingFinisher {
void finish();
@@ -66,8 +83,32 @@ public class HandwritingIme extends InputMethodService {
private void onStylusEvent(@Nullable MotionEvent event) {
// TODO Hookup recognizer here
- if (event.getAction() == MotionEvent.ACTION_UP) {
- sendKeyChar((char) (56 + new Random().nextInt(66)));
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP: {
+ if (areRichGesturesEnabled()) {
+ Bundle bundle = new Bundle();
+ bundle.putInt("operation", mRichGestureMode);
+ bundle.putFloat("left", mRichGestureStartPoint.x);
+ bundle.putFloat("top", mRichGestureStartPoint.y);
+ bundle.putFloat("right", event.getX());
+ bundle.putFloat("bottom", event.getY());
+ performPrivateCommand("android.widget.RichGesture", bundle);
+
+ Log.d(TAG, "Sending RichGesture " + mRichGestureMode + " (Screen) Left: "
+ + mRichGestureStartPoint.x + ", Top: " + mRichGestureStartPoint.y
+ + ", Right: " + event.getX() + ", Bottom: " + event.getY());
+ } else {
+ // insert random ASCII char
+ sendKeyChar((char) (56 + new Random().nextInt(66)));
+ }
+ return;
+ }
+ case MotionEvent.ACTION_DOWN: {
+ if (areRichGesturesEnabled()) {
+ mRichGestureStartPoint = new PointF(event.getX(), event.getY());
+ }
+ return;
+ }
}
}
@@ -81,19 +122,44 @@ public class HandwritingIme extends InputMethodService {
view.setPadding(0, 0, 0, 0);
view.addView(inner, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, height));
- TextView text = new TextView(this);
- text.setText("Handwriting IME");
- text.setTextSize(13f);
- text.setTextColor(getColor(android.R.color.white));
- text.setGravity(Gravity.CENTER);
- text.setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT, height));
- view.addView(text);
- inner.setBackgroundColor(0xff0110fe); // blue
+
+ view.addView(getRichGestureActionsSpinner());
+ inner.setBackgroundColor(getColor(R.color.abc_tint_spinner));
return view;
}
+ private View getRichGestureActionsSpinner() {
+ if (mRichGestureModeSpinner != null) {
+ return mRichGestureModeSpinner;
+ }
+ //get the spinner from the xml.
+ mRichGestureModeSpinner = new Spinner(this);
+ mRichGestureModeSpinner.setPadding(100, 0, 100, 0);
+ mRichGestureModeSpinner.setTooltipText("Handwriting IME mode");
+ String[] items =
+ new String[] { "Handwriting IME - Rich gesture disabled", "Rich gesture SELECT",
+ "Rich gesture DELETE", "Rich gesture DELETE SPACE",
+ "Rich gesture INSERT" };
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_dropdown_item, items);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mRichGestureModeSpinner.setAdapter(adapter);
+ mRichGestureModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mRichGestureMode = position;
+ Log.d(TAG, "Setting RichGesture Mode " + mRichGestureMode);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ mRichGestureMode = OP_NONE;
+ }
+ });
+ return mRichGestureModeSpinner;
+ }
+
public void onPrepareStylusHandwriting() {
Log.d(TAG, "onPrepareStylusHandwriting ");
if (mInk == null) {
@@ -118,4 +184,22 @@ public class HandwritingIme extends InputMethodService {
((ViewGroup) mInk.getParent()).removeView(mInk);
mInk = null;
}
+
+ @Override
+ public boolean onEvaluateFullscreenMode() {
+ return false;
+ }
+
+ boolean performPrivateCommand(String action, Bundle bundle) {
+ if (!getCurrentInputStarted()) {
+ Log.e(TAG, "Input hasnt started, can't performPrivateCommand");
+ return false;
+ }
+
+ return getCurrentInputConnection().performPrivateCommand(action, bundle);
+ }
+
+ private boolean areRichGesturesEnabled() {
+ return mRichGestureMode != OP_NONE;
+ }
}
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
index 87a5b900cc18..c9e429b6f4c8 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -30,7 +30,7 @@ import android.view.WindowManager;
import android.view.WindowMetrics;
class InkView extends View {
- private static final long FINISH_TIMEOUT = 2500;
+ private static final long FINISH_TIMEOUT = 600;
private final HandwritingIme.HandwritingFinisher mHwCanceller;
private final HandwritingIme.StylusConsumer mConsumer;
private final int mTopInset;
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 7490d3f2b50c..ab83997c67fc 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -114,6 +114,63 @@ public class StagedInstallInternalTest {
Uninstall.packages(TestApp.A, TestApp.B);
}
+ private boolean isSystem(PackageInfo info) {
+ return (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ private boolean isUpdatedSystem(PackageInfo info) {
+ return (info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ }
+
+ @Test
+ public void testUpdateSystemApp_InstallV2() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+ PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ PackageInfo info;
+ // Check factory version
+ info = pm.getPackageInfo(TestApp.A,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isFalse();
+ // Check active version
+ info = pm.getPackageInfo(TestApp.A, PackageManager.PackageInfoFlags.of(0));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isFalse();
+
+ Install.single(TestApp.A2).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Check factory version
+ info = pm.getPackageInfo(TestApp.A,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isFalse();
+ // Check active version
+ info = pm.getPackageInfo(TestApp.A, PackageManager.PackageInfoFlags.of(0));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isTrue();
+ }
+
+ @Test
+ public void testUpdateSystemApp_PostInstallV2() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ PackageInfo info;
+ // Check factory version
+ info = pm.getPackageInfo(TestApp.A,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isFalse();
+ // Check active version
+ info = pm.getPackageInfo(TestApp.A, PackageManager.PackageInfoFlags.of(0));
+ assertThat(isSystem(info)).isTrue();
+ assertThat(isUpdatedSystem(info)).isTrue();
+ }
+
@Test
public void testDuplicateApkInApexShouldFail_Commit() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -403,7 +460,8 @@ public class StagedInstallInternalTest {
{
PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
assertThat(apex.getLongVersionCode()).isEqualTo(1);
- assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
+ .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
.isEqualTo(ApplicationInfo.FLAG_INSTALLED);
assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
@@ -414,7 +472,8 @@ public class StagedInstallInternalTest {
assertThat(apex.getLongVersionCode()).isEqualTo(1);
assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
.isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
}
@@ -425,7 +484,8 @@ public class StagedInstallInternalTest {
{
PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
assertThat(apex.getLongVersionCode()).isEqualTo(2);
- assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
+ .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
.isEqualTo(ApplicationInfo.FLAG_INSTALLED);
assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
@@ -436,7 +496,8 @@ public class StagedInstallInternalTest {
assertThat(apex.getLongVersionCode()).isEqualTo(1);
assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
.isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
}
}
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index f60b4d6aad1e..7e0a55ff3f3e 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -95,6 +95,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
"/system/apex/test.rebootless_apex_v*.apex",
"/data/apex/active/test.apex.rebootless*.apex",
+ "/system/app/TestApp/TestAppAv1.apk",
TEST_VENDOR_APEX_ALLOW_LIST);
}
@@ -163,6 +164,25 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
/**
+ * Tests app info flags are set correctly when updating a system app.
+ */
+ @Test
+ public void testUpdateSystemApp() throws Exception {
+ // Push TestAppAv1.apk to /system
+ final File apkFile = mHostUtils.getTestFile(APK_A);
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ assertTrue(getDevice().pushFile(apkFile, "/system/app/TestApp/" + apkFile.getName()));
+ getDevice().reboot();
+
+ runPhase("testUpdateSystemApp_InstallV2");
+ getDevice().reboot();
+ runPhase("testUpdateSystemApp_PostInstallV2");
+ }
+
+ /**
* Tests that duplicate packages in apk-in-apex and apk should fail to install.
*/
@Test
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index b7f5b15f72ac..f183a9b1d46c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -20,6 +20,7 @@ import android.content.Intent;
import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.AlwaysOnHotwordDetector.Callback;
import android.service.voice.AlwaysOnHotwordDetector.EventPayload;
+import android.service.voice.HotwordDetector;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
@@ -83,16 +84,24 @@ public class MainInteractionService extends VoiceInteractionService {
break;
case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED:
Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED");
- Intent enroll = mHotwordDetector.createEnrollIntent();
- Log.i(TAG, "Need to enroll with " + enroll);
+ try {
+ Intent enroll = mHotwordDetector.createEnrollIntent();
+ Log.i(TAG, "Need to enroll with " + enroll);
+ } catch (HotwordDetector.IllegalDetectorStateException e) {
+ Log.e(TAG, "createEnrollIntent failed", e);
+ }
break;
case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED:
Log.i(TAG, "STATE_KEYPHRASE_ENROLLED - starting recognition");
- if (mHotwordDetector.startRecognition(
- AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) {
- Log.i(TAG, "startRecognition succeeded");
- } else {
- Log.i(TAG, "startRecognition failed");
+ try {
+ if (mHotwordDetector.startRecognition(
+ AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) {
+ Log.i(TAG, "startRecognition succeeded");
+ } else {
+ Log.i(TAG, "startRecognition failed");
+ }
+ } catch (HotwordDetector.IllegalDetectorStateException e) {
+ Log.e(TAG, "startRecognition failed", e);
}
break;
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 1fe13fe97fbe..06cbeb5368a5 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -124,16 +124,6 @@ public class WindowManagerPermissionTests extends TestCase {
@SmallTest
public void testSET_ORIENTATION() {
try {
- mWm.updateRotation(true, false);
- fail("IWindowManager.updateRotation did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.freezeRotation(-1);
fail("IWindowManager.freezeRotation did not throw SecurityException as"
+ " expected");
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index f924b2e9b932..54b3c400af4f 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -23,7 +23,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
@@ -277,6 +276,7 @@ public class VcnManagementServiceTest {
@Test
public void testSystemReady() throws Exception {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register();
@@ -494,10 +494,8 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
-
- // Verify teardown after delay
- mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll();
+
verify(vcn).teardownAsynchronously();
verify(mMockPolicyListener).onPolicyChanged();
}
@@ -523,92 +521,6 @@ public class VcnManagementServiceTest {
assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
}
- /**
- * Tests an intermediate state where carrier privileges are marked as lost before active data
- * subId changes during a SIM ejection.
- *
- * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
- * immediately.
- */
- @Test
- public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
- throws Exception {
- setupActiveSubscription(TEST_UUID_2);
-
- final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
- final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
-
- // Simulate privileges lost
- triggerSubscriptionTrackerCbAndGetSnapshot(
- TEST_SUBSCRIPTION_ID,
- TEST_UUID_2,
- Collections.emptySet(),
- Collections.emptyMap(),
- false /* hasCarrierPrivileges */);
-
- // Verify teardown after delay
- mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
- mTestLooper.dispatchAll();
- verify(vcn).teardownAsynchronously();
- }
-
- @Test
- public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
- throws Exception {
- setupActiveSubscription(TEST_UUID_2);
-
- final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
- final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
-
- // Simulate SIM unloaded
- triggerSubscriptionTrackerCbAndGetSnapshot(
- INVALID_SUBSCRIPTION_ID,
- null /* activeDataSubscriptionGroup */,
- Collections.emptySet(),
- Collections.emptyMap(),
- false /* hasCarrierPrivileges */);
-
- // Simulate new SIM loaded right during teardown delay.
- mTestLooper.moveTimeForward(
- VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
- mTestLooper.dispatchAll();
- triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
-
- // Verify that even after the full timeout duration, the VCN instance is not torn down
- mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
- mTestLooper.dispatchAll();
- verify(vcn, never()).teardownAsynchronously();
- }
-
- @Test
- public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
- setupActiveSubscription(TEST_UUID_2);
-
- final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
- final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
-
- // Simulate SIM unloaded
- triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
-
- // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
- // vcnInstance.
- mTestLooper.moveTimeForward(
- VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
- mTestLooper.dispatchAll();
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
- triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
- final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
-
- // Verify that new instance was different, and the old one was torn down
- assertTrue(oldInstance != newInstance);
- verify(oldInstance).teardownAsynchronously();
-
- // Verify that even after the full timeout duration, the new VCN instance is not torn down
- mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
- mTestLooper.dispatchAll();
- verify(newInstance, never()).teardownAsynchronously();
- }
-
@Test
public void testPackageChangeListenerRegistered() throws Exception {
verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
@@ -998,6 +910,8 @@ public class VcnManagementServiceTest {
private void setupSubscriptionAndStartVcn(
int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
+
triggerSubscriptionTrackerCbAndGetSnapshot(
subGrp,
Collections.singleton(subGrp),
@@ -1093,6 +1007,7 @@ public class VcnManagementServiceTest {
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
final ArgumentCaptor<NetworkCallback> captor =
ArgumentCaptor.forClass(NetworkCallback.class);
@@ -1337,15 +1252,14 @@ public class VcnManagementServiceTest {
true /* isActive */,
true /* hasCarrierPrivileges */);
- // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
- // timeout so the VCN goes inactive.
+ // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes
+ // inactive.
final TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(
TEST_UUID_1,
Collections.singleton(TEST_UUID_1),
Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
false /* hasCarrierPrivileges */);
- mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
mTestLooper.dispatchAll();
// Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index bfb32854a374..7efe3c3472fa 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -24,6 +24,7 @@ package {
}
toolSources = [
+ "cmd/ApkInfo.cpp",
"cmd/Command.cpp",
"cmd/Compile.cpp",
"cmd/Convert.cpp",
@@ -36,6 +37,7 @@ toolSources = [
cc_defaults {
name: "aapt2_defaults",
+ cpp_std: "gnu++2b",
cflags: [
"-Wall",
"-Werror",
@@ -135,7 +137,6 @@ cc_library_host_static {
"text/Printer.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
- "util/BigBuffer.cpp",
"util/Files.cpp",
"util/Util.cpp",
"Debug.cpp",
@@ -152,12 +153,12 @@ cc_library_host_static {
"ResourceUtils.cpp",
"ResourceValues.cpp",
"SdkConstants.cpp",
- "StringPool.cpp",
"trace/TraceBuffer.cpp",
"xml/XmlActionExecutor.cpp",
"xml/XmlDom.cpp",
"xml/XmlPullParser.cpp",
"xml/XmlUtil.cpp",
+ "ApkInfo.proto",
"Configuration.proto",
"Resources.proto",
"ResourcesInternal.proto",
@@ -190,6 +191,7 @@ cc_test_host {
"integration-tests/CompileTest/**/*",
"integration-tests/CommandTests/**/*",
"integration-tests/ConvertTest/**/*",
+ "integration-tests/DumpTest/**/*",
],
}
diff --git a/tools/aapt2/ApkInfo.proto b/tools/aapt2/ApkInfo.proto
new file mode 100644
index 000000000000..80bdccbc4dd2
--- /dev/null
+++ b/tools/aapt2/ApkInfo.proto
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+import "frameworks/base/tools/aapt2/Resources.proto";
+
+package aapt.pb;
+
+option java_package = "com.android.aapt";
+
+// Top level message representing data extracted from the APK for 'apkinfo'
+// command.
+message ApkInfo {
+ message XmlFile {
+ string path = 1;
+ XmlNode root = 2;
+ }
+
+ Badging badging = 1;
+ ResourceTable resource_table = 2;
+ repeated XmlFile xml_files = 3;
+}
+
+// Data extracted from the manifest of the APK.
+message Badging {
+ PackageInfo package = 1;
+ Application application = 2;
+ UsesSdk uses_sdk = 3;
+ UsesConfiguration uses_configuration = 4;
+ SupportsScreen supports_screen = 5;
+ SupportsInput supports_input = 6;
+ LaunchableActivity launchable_activity = 7;
+ LeanbackLaunchableActivity leanback_launchable_activity = 8;
+ StaticLibrary static_library = 9;
+ SdkLibrary sdk_library = 10;
+ Overlay overlay = 11;
+ PackageVerifier package_verifier = 12;
+ CompatibleScreens compatible_screens = 13;
+ Architectures architectures = 14;
+ SupportsGlTexture supports_gl_texture = 15;
+ Components components = 16;
+
+ repeated string locales = 17;
+ repeated int32 densities = 18;
+
+ repeated FeatureGroup feature_groups = 53;
+ repeated UsesPermission uses_permissions = 54;
+ repeated Permission permissions = 55;
+ repeated UsesLibrary uses_libraries = 56;
+ repeated UsesStaticLibrary uses_static_libraries = 57;
+ repeated UsesSdkLibrary uses_sdk_libraries = 58;
+ repeated UsesNativeLibrary uses_native_libraries = 59;
+ repeated UsesPackage uses_packages = 51;
+
+ repeated Metadata metadata = 62;
+ repeated Property properties = 63;
+}
+
+// Information extracted about package from <manifest> and
+// <original-package> tags.
+message PackageInfo {
+ enum InstallLocation {
+ DEFAULT_INSTALL_LOCATION = 0;
+ AUTO = 1;
+ INTERNAL_ONLY = 2;
+ PREFER_EXTERNAL = 3;
+ }
+
+ string package = 1;
+ int32 version_code = 2;
+ string version_name = 3;
+
+ string split = 4;
+
+ string platform_version_name = 5;
+ string platform_version_code = 6;
+
+ int32 compile_sdk_version = 7;
+ string compile_sdk_version_codename = 8;
+
+ InstallLocation install_location = 9;
+
+ string original_package = 10;
+}
+
+// Information extracted from <application> element.
+message Application {
+ string label = 1;
+ string icon = 2;
+ string banner = 3;
+
+ bool test_only = 4;
+ bool game = 5;
+ bool debuggable = 6;
+
+ map<string, string> locale_labels = 8;
+ map<int32, string> density_icons = 9;
+}
+
+// Components defined in the APK.
+message Components {
+ bool main = 1;
+ bool other_activities = 2;
+ bool other_receivers = 3;
+ bool other_services = 4;
+
+ repeated string provided_components = 5;
+}
+
+// Application's min and target SDKs.
+message UsesSdk {
+ oneof min_sdk {
+ int32 min_sdk_version = 2;
+ string min_sdk_version_name = 3;
+ }
+ int32 max_sdk_version = 4;
+ oneof target_sdk {
+ int32 target_sdk_version = 5;
+ string target_sdk_version_name = 6;
+ }
+}
+
+message UsesConfiguration {
+ int32 req_touch_screen = 1;
+ int32 req_keyboard_type = 2;
+ int32 req_hard_keyboard = 3;
+ int32 req_navigation = 4;
+ int32 req_five_way_nav = 5;
+}
+
+// Screens supported by this application.
+message SupportsScreen {
+ enum ScreenType {
+ UNSPECIFIED_SCREEN_TYPE = 0;
+ SMALL = 1;
+ NORMAL = 2;
+ LARGE = 3;
+ XLARGE = 4;
+ }
+ repeated ScreenType screens = 1;
+ bool supports_any_densities = 2;
+ int32 requires_smallest_width_dp = 3;
+ int32 compatible_width_limit_dp = 4;
+ int32 largest_width_limit_dp = 5;
+}
+
+// Inputs supported by this application.
+message SupportsInput {
+ repeated string inputs = 1;
+}
+
+// Information about used features which is extracted from <uses-permission>
+// elements or implied from permissions.
+message Feature {
+ message ImpliedData {
+ bool from_sdk_23_permission = 1;
+ repeated string reasons = 2;
+ }
+
+ string name = 1;
+ bool required = 2;
+ int32 version = 3;
+
+ ImpliedData implied_data = 4;
+}
+
+message FeatureGroup {
+ string label = 1;
+ int32 open_gles_version = 2;
+ repeated Feature features = 3;
+}
+
+// Information about permission requested by the application.
+message UsesPermission {
+ message PermissionFlags {
+ bool never_for_location = 1;
+ }
+
+ string name = 1;
+ int32 max_sdk_version = 2;
+ bool required = 3;
+ bool implied = 4;
+ bool sdk23_and_above = 5;
+
+ repeated string required_features = 6;
+ repeated string required_not_features = 7;
+
+ PermissionFlags permission_flags = 8;
+}
+
+// Permission defined by the application.
+message Permission {
+ string name = 1;
+}
+
+// Data extracted about launchable activity. Launchable activity is an entry
+// point on phone and tablet devices.
+message LaunchableActivity {
+ string name = 1;
+ string icon = 2;
+ string label = 3;
+}
+
+// Data extracted about leanback launchable activity. Leanback launchable
+// activity is an entry point on TV devices.
+message LeanbackLaunchableActivity {
+ string name = 1;
+ string icon = 2;
+ string label = 3;
+ string banner = 4;
+}
+
+// Library used by the application.
+message UsesLibrary {
+ string name = 1;
+ bool required = 2;
+}
+
+// Static library this APK declares.
+message StaticLibrary {
+ string name = 1;
+ int32 version = 2;
+ int32 version_major = 3;
+}
+
+// Static library used by the application.
+message UsesStaticLibrary {
+ string name = 1;
+ int32 version = 2;
+ int32 version_major = 3;
+ repeated string certificates = 4;
+}
+
+// SDK library this APK declares.
+message SdkLibrary {
+ string name = 1;
+ int32 version_major = 2;
+}
+
+// SDK library used by the application.
+message UsesSdkLibrary {
+ string name = 1;
+ int32 version_major = 2;
+ repeated string certificates = 3;
+}
+
+// Native library used by the application.
+message UsesNativeLibrary {
+ string name = 1;
+ bool required = 2;
+}
+
+// Information extracted from <meta-data> elements defined across
+// AndroidManifest.xml.
+message Metadata {
+ string name = 1;
+ oneof value {
+ string value_string = 2;
+ int32 value_int = 3;
+ }
+ oneof resource {
+ string resource_string = 4;
+ int32 resource_int = 5;
+ }
+}
+
+// Information about overlay that is declared in the APK.
+message Overlay {
+ string target_package = 1;
+ int32 priority = 2;
+ bool static = 3;
+ string required_property_name = 4;
+ string required_property_value = 5;
+}
+
+// Data extracted from <package-verifier> element.
+message PackageVerifier {
+ string name = 1;
+ string public_key = 2;
+}
+
+// External packages used by the application
+message UsesPackage {
+ string name = 1;
+ string package_type = 2;
+ int32 version = 3;
+ int32 version_major = 4;
+ repeated string certificates = 5;
+}
+
+// Open GL textures format supported by the current application.
+message SupportsGlTexture {
+ repeated string name = 1;
+}
+
+// Screens compatible with the application.
+message CompatibleScreens {
+ message Screen {
+ int32 size = 1;
+ int32 density = 2;
+ }
+
+ repeated Screen screens = 1;
+}
+
+// Architectures supported by the application.
+message Architectures {
+ repeated string architectures = 1;
+ repeated string alt_architectures = 2;
+}
+
+// Information extracted from <property> elements defined across
+// AndroidManifest.xml.
+message Property {
+ string name = 1;
+ oneof value {
+ string value_string = 2;
+ int32 value_int = 3;
+ }
+ oneof resource {
+ string resource_string = 4;
+ int32 resource_int = 5;
+ }
+} \ No newline at end of file
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index f47d66ea5e87..dfa229173373 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -17,6 +17,7 @@
#include "Debug.h"
#include <androidfw/TypeWrappers.h>
+#include <androidfw/Util.h>
#include <format/binary/ResChunkPullParser.h>
#include <algorithm>
@@ -273,7 +274,7 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
printer->Indent();
for (const auto& type : package.types) {
printer->Print("type ");
- printer->Print(to_string(type.type));
+ printer->Print(type.named_type.to_string());
if (type.id) {
printer->Print(StringPrintf(" id=%02x", type.id.value()));
}
@@ -287,7 +288,7 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
printer->Print(" ");
// Write the name without the package (this is obvious and too verbose).
- printer->Print(to_string(type.type));
+ printer->Print(type.named_type.to_string());
printer->Print("/");
printer->Print(entry.name);
@@ -547,7 +548,7 @@ void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer)
const auto policy_subsection = StringPrintf(R"(policies="%s")",
android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
const auto value =
- StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str());
+ StringPrintf("%s/%s", type->named_type.to_string().data(), entry->name.c_str());
items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
}
}
@@ -592,12 +593,12 @@ using namespace android;
class ChunkPrinter {
public:
- ChunkPrinter(const void* data, size_t len, Printer* printer, IDiagnostics* diag)
+ ChunkPrinter(const void* data, size_t len, Printer* printer, android::IDiagnostics* diag)
: data_(data), data_len_(len), printer_(printer), diag_(diag) {
}
void PrintChunkHeader(const ResChunk_header* chunk) {
- switch (util::DeviceToHost16(chunk->type)) {
+ switch (android::util::DeviceToHost16(chunk->type)) {
case RES_STRING_POOL_TYPE:
printer_->Print("[RES_STRING_POOL_TYPE]");
break;
@@ -620,13 +621,14 @@ class ChunkPrinter {
break;
}
- printer_->Print(StringPrintf(" chunkSize: %u", util::DeviceToHost32(chunk->size)));
- printer_->Print(StringPrintf(" headerSize: %u", util::DeviceToHost32(chunk->headerSize)));
+ printer_->Print(StringPrintf(" chunkSize: %u", android::util::DeviceToHost32(chunk->size)));
+ printer_->Print(
+ StringPrintf(" headerSize: %u", android::util::DeviceToHost32(chunk->headerSize)));
}
bool PrintTable(const ResTable_header* chunk) {
printer_->Print(
- StringPrintf(" Package count: %u\n", util::DeviceToHost32(chunk->packageCount)));
+ StringPrintf(" Package count: %u\n", android::util::DeviceToHost32(chunk->packageCount)));
// Print the chunks contained within the table
printer_->Indent();
@@ -639,9 +641,10 @@ class ChunkPrinter {
void PrintResValue(const Res_value* value, const ConfigDescription& config,
const ResourceType* type) {
printer_->Print("[Res_value]");
- printer_->Print(StringPrintf(" size: %u", util::DeviceToHost32(value->size)));
- printer_->Print(StringPrintf(" dataType: 0x%02x", util::DeviceToHost32(value->dataType)));
- printer_->Print(StringPrintf(" data: 0x%08x", util::DeviceToHost32(value->data)));
+ printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(value->size)));
+ printer_->Print(
+ StringPrintf(" dataType: 0x%02x", android::util::DeviceToHost32(value->dataType)));
+ printer_->Print(StringPrintf(" data: 0x%08x", android::util::DeviceToHost32(value->data)));
if (type) {
auto item =
@@ -655,19 +658,23 @@ class ChunkPrinter {
}
bool PrintTableType(const ResTable_type* chunk) {
- printer_->Print(StringPrintf(" id: 0x%02x", util::DeviceToHost32(chunk->id)));
+ printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
printer_->Print(StringPrintf(
- " name: %s", util::GetString(type_pool_, util::DeviceToHost32(chunk->id) - 1).c_str()));
- printer_->Print(StringPrintf(" flags: 0x%02x", util::DeviceToHost32(chunk->flags)));
- printer_->Print(StringPrintf(" entryCount: %u", util::DeviceToHost32(chunk->entryCount)));
- printer_->Print(StringPrintf(" entryStart: %u", util::DeviceToHost32(chunk->entriesStart)));
+ " name: %s",
+ android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1)
+ .c_str()));
+ printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags)));
+ printer_->Print(
+ StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount)));
+ printer_->Print(
+ StringPrintf(" entryStart: %u", android::util::DeviceToHost32(chunk->entriesStart)));
ConfigDescription config;
config.copyFromDtoH(chunk->config);
printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str()));
- const ResourceType* type =
- ParseResourceType(util::GetString(type_pool_, util::DeviceToHost32(chunk->id) - 1));
+ const ResourceType* type = ParseResourceType(
+ android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1));
printer_->Indent();
@@ -682,35 +689,42 @@ class ChunkPrinter {
: "[ResTable_entry]");
printer_->Print(StringPrintf(" id: 0x%04x", it.index()));
printer_->Print(StringPrintf(
- " name: %s", util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)).c_str()));
- printer_->Print(StringPrintf(" keyIndex: %u", util::DeviceToHost32(entry->key.index)));
- printer_->Print(StringPrintf(" size: %u", util::DeviceToHost32(entry->size)));
- printer_->Print(StringPrintf(" flags: 0x%04x", util::DeviceToHost32(entry->flags)));
+ " name: %s",
+ android::util::GetString(key_pool_, android::util::DeviceToHost32(entry->key.index))
+ .c_str()));
+ printer_->Print(
+ StringPrintf(" keyIndex: %u", android::util::DeviceToHost32(entry->key.index)));
+ printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(entry->size)));
+ printer_->Print(StringPrintf(" flags: 0x%04x", android::util::DeviceToHost32(entry->flags)));
printer_->Indent();
if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
auto map_entry = (const ResTable_map_entry*)entry;
- printer_->Print(StringPrintf(" count: 0x%04x", util::DeviceToHost32(map_entry->count)));
printer_->Print(
- StringPrintf(" parent: 0x%08x\n", util::DeviceToHost32(map_entry->parent.ident)));
+ StringPrintf(" count: 0x%04x", android::util::DeviceToHost32(map_entry->count)));
+ printer_->Print(StringPrintf(" parent: 0x%08x\n",
+ android::util::DeviceToHost32(map_entry->parent.ident)));
// Print the name and value mappings
- auto maps =
- (const ResTable_map*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
- for (size_t i = 0, count = util::DeviceToHost32(map_entry->count); i < count; i++) {
+ auto maps = (const ResTable_map*)((const uint8_t*)entry +
+ android::util::DeviceToHost32(entry->size));
+ for (size_t i = 0, count = android::util::DeviceToHost32(map_entry->count); i < count;
+ i++) {
PrintResValue(&(maps[i].value), config, type);
printer_->Print(StringPrintf(
" name: %s name-id:%d\n",
- util::GetString(key_pool_, util::DeviceToHost32(maps[i].name.ident)).c_str(),
- util::DeviceToHost32(maps[i].name.ident)));
+ android::util::GetString(key_pool_, android::util::DeviceToHost32(maps[i].name.ident))
+ .c_str(),
+ android::util::DeviceToHost32(maps[i].name.ident)));
}
} else {
printer_->Print("\n");
// Print the value of the entry
- auto value = (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
+ auto value =
+ (const Res_value*)((const uint8_t*)entry + android::util::DeviceToHost32(entry->size));
PrintResValue(value, config, type);
}
@@ -735,33 +749,37 @@ class ChunkPrinter {
return;
}
- pool->setTo(chunk,
- util::DeviceToHost32((reinterpret_cast<const ResChunk_header*>(chunk))->size));
+ pool->setTo(chunk, android::util::DeviceToHost32(
+ (reinterpret_cast<const ResChunk_header*>(chunk))->size));
printer_->Print("\n");
for (size_t i = 0; i < pool->size(); i++) {
- printer_->Print(StringPrintf("#%zd : %s\n", i, util::GetString(*pool, i).c_str()));
+ printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
}
}
bool PrintPackage(const ResTable_package* chunk) {
- printer_->Print(StringPrintf(" id: 0x%02x", util::DeviceToHost32(chunk->id)));
+ printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
size_t len = strnlen16((const char16_t*)chunk->name, std::size(chunk->name));
std::u16string package_name(len, u'\0');
package_name.resize(len);
for (size_t i = 0; i < len; i++) {
- package_name[i] = util::DeviceToHost16(chunk->name[i]);
+ package_name[i] = android::util::DeviceToHost16(chunk->name[i]);
}
printer_->Print(StringPrintf("name: %s", String8(package_name.c_str()).c_str()));
- printer_->Print(StringPrintf(" typeStrings: %u", util::DeviceToHost32(chunk->typeStrings)));
printer_->Print(
- StringPrintf(" lastPublicType: %u", util::DeviceToHost32(chunk->lastPublicType)));
- printer_->Print(StringPrintf(" keyStrings: %u", util::DeviceToHost32(chunk->keyStrings)));
- printer_->Print(StringPrintf(" lastPublicKey: %u", util::DeviceToHost32(chunk->lastPublicKey)));
- printer_->Print(StringPrintf(" typeIdOffset: %u\n", util::DeviceToHost32(chunk->typeIdOffset)));
+ StringPrintf(" typeStrings: %u", android::util::DeviceToHost32(chunk->typeStrings)));
+ printer_->Print(
+ StringPrintf(" lastPublicType: %u", android::util::DeviceToHost32(chunk->lastPublicType)));
+ printer_->Print(
+ StringPrintf(" keyStrings: %u", android::util::DeviceToHost32(chunk->keyStrings)));
+ printer_->Print(
+ StringPrintf(" lastPublicKey: %u", android::util::DeviceToHost32(chunk->lastPublicKey)));
+ printer_->Print(
+ StringPrintf(" typeIdOffset: %u\n", android::util::DeviceToHost32(chunk->typeIdOffset)));
// Print the chunks contained within the table
printer_->Indent();
@@ -776,7 +794,7 @@ class ChunkPrinter {
auto chunk = parser.chunk();
PrintChunkHeader(chunk);
- switch (util::DeviceToHost16(chunk->type)) {
+ switch (android::util::DeviceToHost16(chunk->type)) {
case RES_STRING_POOL_TYPE:
PrintStringPool(reinterpret_cast<const ResStringPool_header*>(chunk));
break;
@@ -802,7 +820,7 @@ class ChunkPrinter {
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
@@ -815,11 +833,11 @@ class ChunkPrinter {
}
private:
- const Source source_;
+ const android::Source source_;
const void* data_;
const size_t data_len_;
Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
// The standard value string pool for resource values.
ResStringPool value_pool_;
@@ -832,12 +850,13 @@ class ChunkPrinter {
// in this table.
ResStringPool key_pool_;
- StringPool out_pool_;
+ android::StringPool out_pool_;
};
} // namespace
-void Debug::DumpChunks(const void* data, size_t len, Printer* printer, IDiagnostics* diag) {
+void Debug::DumpChunks(const void* data, size_t len, Printer* printer,
+ android::IDiagnostics* diag) {
ChunkPrinter chunk_printer(data, len, printer, diag);
chunk_printer.Print();
}
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 4da92044cf2a..8015249e7d36 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -40,7 +40,8 @@ struct Debug {
static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer);
static void DumpOverlayable(const ResourceTable& table, text::Printer* printer);
- static void DumpChunks(const void* data, size_t len, text::Printer* printer, IDiagnostics* diag);
+ static void DumpChunks(const void* data, size_t len, text::Printer* printer,
+ android::IDiagnostics* diag);
};
} // namespace aapt
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 30deb5555b21..c89db725e6f2 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -13,86 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef AAPT_DIAGNOSTICS_H
-#define AAPT_DIAGNOSTICS_H
+#ifndef AAPT_DIAGNOSTICS_H_
+#define AAPT_DIAGNOSTICS_H_
#include <iostream>
#include <sstream>
#include <string>
#include "android-base/macros.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
-
-#include "Source.h"
#include "util/Util.h"
namespace aapt {
-
-struct DiagMessageActual {
- Source source;
- std::string message;
-};
-
-struct DiagMessage {
- public:
- DiagMessage() = default;
-
- explicit DiagMessage(const android::StringPiece& src) : source_(src) {}
-
- explicit DiagMessage(const Source& src) : source_(src) {}
-
- explicit DiagMessage(size_t line) : source_(Source().WithLine(line)) {}
-
- template <typename T>
- DiagMessage& operator<<(const T& value) {
- message_ << value;
- return *this;
- }
-
- DiagMessageActual Build() const {
- return DiagMessageActual{source_, message_.str()};
- }
-
- private:
- Source source_;
- std::stringstream message_;
-};
-
-template <>
-inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
- message_ << android::StringPiece16(value);
- return *this;
-}
-
-struct IDiagnostics {
- virtual ~IDiagnostics() = default;
-
- enum class Level { Note, Warn, Error };
-
- virtual void Log(Level level, DiagMessageActual& actualMsg) = 0;
-
- virtual void Error(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Error, actual);
- }
-
- virtual void Warn(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Warn, actual);
- }
-
- virtual void Note(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Note, actual);
- }
-};
-
-class StdErrDiagnostics : public IDiagnostics {
+class StdErrDiagnostics : public android::IDiagnostics {
public:
StdErrDiagnostics() = default;
- void Log(Level level, DiagMessageActual& actual_msg) override {
+ void Log(Level level, android::DiagMessageActual& actual_msg) override {
const char* tag;
switch (level) {
@@ -125,31 +64,6 @@ class StdErrDiagnostics : public IDiagnostics {
DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics);
};
-class SourcePathDiagnostics : public IDiagnostics {
- public:
- SourcePathDiagnostics(const Source& src, IDiagnostics* diag)
- : source_(src), diag_(diag) {}
-
- void Log(Level level, DiagMessageActual& actual_msg) override {
- actual_msg.source.path = source_.path;
- diag_->Log(level, actual_msg);
- if (level == Level::Error) {
- error = true;
- }
- }
-
- bool HadError() {
- return error;
- }
-
- private:
- Source source_;
- IDiagnostics* diag_;
- bool error = false;
-
- DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
-};
-
} // namespace aapt
-#endif /* AAPT_DIAGNOSTICS_H */
+#endif /* AAPT_DIAGNOSTICS_H_ */
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 830bc5fa36aa..9b9cde2f37da 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -72,12 +72,13 @@ static ApkFormat DetermineApkFormat(io::IFileCollection* apk) {
}
}
-std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
- Source source(path);
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path,
+ android::IDiagnostics* diag) {
+ android::Source source(path);
std::string error;
std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
if (apk == nullptr) {
- diag->Error(DiagMessage(path) << "failed opening zip: " << error);
+ diag->Error(android::DiagMessage(path) << "failed opening zip: " << error);
return {};
}
@@ -88,13 +89,14 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, I
case ApkFormat::kProto:
return LoadProtoApkFromFileCollection(source, std::move(apk), diag);
default:
- diag->Error(DiagMessage(path) << "could not identify format of APK");
+ diag->Error(android::DiagMessage(path) << "could not identify format of APK");
return {};
}
}
std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
- const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ const android::Source& source, unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag) {
std::unique_ptr<ResourceTable> table;
io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
@@ -102,20 +104,20 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
pb::ResourceTable pb_table;
std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
if (in == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
return {};
}
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_table)) {
- diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
return {};
}
std::string error;
table = util::make_unique<ResourceTable>(ResourceTable::Validation::kDisabled);
if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to deserialize " << kProtoResourceTablePath << ": " << error);
return {};
}
@@ -123,27 +125,27 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to find " << kAndroidManifestPath);
return {};
}
std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
if (manifest_in == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath);
return {};
}
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(manifest_in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
return {};
}
std::string error;
std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
if (manifest == nullptr) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to deserialize proto " << kAndroidManifestPath << ": " << error);
return {};
}
@@ -152,7 +154,8 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
}
std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
- const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ const android::Source& source, unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag) {
std::unique_ptr<ResourceTable> table;
io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
@@ -160,7 +163,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
table = util::make_unique<ResourceTable>(ResourceTable::Validation::kDisabled);
std::unique_ptr<io::IData> data = table_file->OpenAsData();
if (data == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kApkResourceTablePath);
return {};
}
BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
@@ -172,13 +175,13 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to find " << kAndroidManifestPath);
return {};
}
std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
if (manifest_data == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath);
return {};
}
@@ -186,7 +189,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
std::unique_ptr<xml::XmlResource> manifest =
xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
if (manifest == nullptr) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to parse binary " << kAndroidManifestPath << ": " << error);
return {};
}
@@ -235,7 +238,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
// Skip resources that are not referenced if requested.
if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage()
+ context->GetDiagnostics()->Note(android::DiagMessage()
<< "Removing resource '" << path << "' from APK.");
}
continue;
@@ -243,14 +246,15 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
if (!filters->Keep(path)) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "Filtered '" << path << "' from APK.");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "Filtered '" << path << "' from APK.");
}
continue;
}
// The resource table needs to be re-serialized since it might have changed.
if (format_ == ApkFormat::kBinary && path == kApkResourceTablePath) {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
// TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
// with sparse entries) b/35389232.
TableFlattener flattener(options, &buffer);
@@ -282,12 +286,12 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
return false;
}
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
- BigBuffer buffer(8192);
+ android::BigBuffer buffer(8192);
XmlFlattenerOptions xml_flattener_options;
xml_flattener_options.use_utf16 = true;
XmlFlattener xml_flattener(&buffer, xml_flattener_options);
if (!xml_flattener.Consume(context, manifest)) {
- context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
+ context->GetDiagnostics()->Error(android::DiagMessage(path) << "flattening failed");
return false;
}
@@ -308,10 +312,10 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
}
std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path,
- IDiagnostics* diag) const {
+ android::IDiagnostics* diag) const {
io::IFile* file = apk_->FindFile(file_path);
if (file == nullptr) {
- diag->Error(DiagMessage() << "failed to find file");
+ diag->Error(android::DiagMessage() << "failed to find file");
return nullptr;
}
@@ -319,34 +323,34 @@ std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_pat
if (format_ == ApkFormat::kProto) {
std::unique_ptr<io::InputStream> in = file->OpenInputStream();
if (!in) {
- diag->Error(DiagMessage() << "failed to open file");
+ diag->Error(android::DiagMessage() << "failed to open file");
return nullptr;
}
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- diag->Error(DiagMessage() << "failed to parse file as proto XML");
+ diag->Error(android::DiagMessage() << "failed to parse file as proto XML");
return nullptr;
}
std::string err;
doc = DeserializeXmlResourceFromPb(pb_node, &err);
if (!doc) {
- diag->Error(DiagMessage() << "failed to deserialize proto XML: " << err);
+ diag->Error(android::DiagMessage() << "failed to deserialize proto XML: " << err);
return nullptr;
}
} else if (format_ == ApkFormat::kBinary) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- diag->Error(DiagMessage() << "failed to open file");
+ diag->Error(android::DiagMessage() << "failed to open file");
return nullptr;
}
std::string err;
doc = xml::Inflate(data->data(), data->size(), &err);
if (!doc) {
- diag->Error(DiagMessage() << "failed to parse file as binary XML: " << err);
+ diag->Error(android::DiagMessage() << "failed to parse file as binary XML: " << err);
return nullptr;
}
}
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 5b6f45ebb38d..a4aff3f8376a 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -46,17 +46,19 @@ class LoadedApk {
// Loads both binary and proto APKs from disk.
static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Loads a proto APK from the given file collection.
static std::unique_ptr<LoadedApk> LoadProtoApkFromFileCollection(
- const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+ const android::Source& source, std::unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag);
// Loads a binary APK from the given file collection.
static std::unique_ptr<LoadedApk> LoadBinaryApkFromFileCollection(
- const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+ const android::Source& source, std::unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag);
- LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+ LoadedApk(const android::Source& source, std::unique_ptr<io::IFileCollection> apk,
std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest,
const ApkFormat& format)
: source_(source),
@@ -82,7 +84,7 @@ class LoadedApk {
return table_.get();
}
- const Source& GetSource() {
+ const android::Source& GetSource() {
return source_;
}
@@ -111,12 +113,13 @@ class LoadedApk {
IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
/** Loads the file as an xml document. */
- std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag) const;
+ std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path,
+ android::IDiagnostics* diag) const;
private:
DISALLOW_COPY_AND_ASSIGN(LoadedApk);
- Source source_;
+ android::Source source_;
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index b249c6c128e1..a0b4dab9b8e5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -24,11 +24,12 @@
#include <iostream>
#include <vector>
+#include "Diagnostics.h"
#include "android-base/stringprintf.h"
#include "android-base/utf8.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
+#include "cmd/ApkInfo.h"
#include "cmd/Command.h"
#include "cmd/Compile.h"
#include "cmd/Convert.h"
@@ -63,7 +64,7 @@ class VersionCommand : public Command {
/** The main entry point of AAPT. */
class MainCommand : public Command {
public:
- explicit MainCommand(text::Printer* printer, IDiagnostics* diagnostics)
+ explicit MainCommand(text::Printer* printer, android::IDiagnostics* diagnostics)
: Command("aapt2"), diagnostics_(diagnostics) {
AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
@@ -72,13 +73,14 @@ class MainCommand : public Command {
AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
AddOptionalSubcommand(util::make_unique<ConvertCommand>());
AddOptionalSubcommand(util::make_unique<VersionCommand>());
+ AddOptionalSubcommand(util::make_unique<ApkInfoCommand>(diagnostics));
}
int Action(const std::vector<std::string>& args) override {
if (args.size() == 0) {
- diagnostics_->Error(DiagMessage() << "no subcommand specified");
+ diagnostics_->Error(android::DiagMessage() << "no subcommand specified");
} else {
- diagnostics_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ diagnostics_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'");
}
Usage(&std::cerr);
@@ -86,7 +88,7 @@ class MainCommand : public Command {
}
private:
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
};
/*
@@ -97,7 +99,7 @@ class MainCommand : public Command {
*/
class DaemonCommand : public Command {
public:
- explicit DaemonCommand(io::FileOutputStream* out, IDiagnostics* diagnostics)
+ explicit DaemonCommand(io::FileOutputStream* out, android::IDiagnostics* diagnostics)
: Command("daemon", "m"), out_(out), diagnostics_(diagnostics) {
SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
"command. The end of an invocation is signaled by providing an empty line.");
@@ -146,7 +148,7 @@ class DaemonCommand : public Command {
private:
io::FileOutputStream* out_;
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
std::optional<std::string> trace_folder_;
};
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 0bb330e26e6f..df8c3b9956d0 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -139,10 +139,10 @@ ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t) {
}
std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s) {
- auto colon = std::find(s.begin(), s.end(), ':');
+ auto dot = std::find(s.begin(), s.end(), '.');
const ResourceType* parsedType;
- if (colon != s.end() && colon != std::prev(s.end())) {
- parsedType = ParseResourceType(s.substr(s.begin(), colon));
+ if (dot != s.end() && dot != std::prev(s.end())) {
+ parsedType = ParseResourceType(s.substr(s.begin(), dot));
} else {
parsedType = ParseResourceType(s);
}
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index b41d8514230b..9cfaf4742ca5 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -25,8 +25,8 @@
#include <tuple>
#include <vector>
-#include "Source.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
#include "utils/JenkinsHash.h"
@@ -228,7 +228,7 @@ struct ResourceFile {
Type type;
// Source
- Source source;
+ android::Source source;
// Exported symbols
std::vector<SourcedResourceName> exported_symbols;
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 8d35eeec2a93..19fd306d5a42 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -102,7 +102,7 @@ struct ParsedResource {
ResourceName name;
ConfigDescription config;
std::string product;
- Source source;
+ android::Source source;
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -117,7 +117,8 @@ struct ParsedResource {
};
// Recursively adds resources to the ResourceTable.
-static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
+static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* diag,
+ ParsedResource* res) {
StringPiece trimmed_comment = util::TrimWhitespace(res->comment);
if (trimmed_comment.size() != res->comment.size()) {
// Only if there was a change do we re-assign.
@@ -175,15 +176,11 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
// Convenient aliases for more readable function calls.
enum { kAllowRawString = true, kNoRawString = false };
-ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table,
- const Source& source,
- const ConfigDescription& config,
+ResourceParser::ResourceParser(android::IDiagnostics* diag, ResourceTable* table,
+ const android::Source& source, const ConfigDescription& config,
const ResourceParserOptions& options)
- : diag_(diag),
- table_(table),
- source_(source),
- config_(config),
- options_(options) {}
+ : diag_(diag), table_(table), source_(source), config_(config), options_(options) {
+}
// Base class Node for representing the various Spans and UntranslatableSections of an XML string.
// This will be used to traverse and flatten the XML string into a single std::string, with all
@@ -245,7 +242,7 @@ class UntranslatableNode : public Node {
// Build a string from XML that converts nested elements into Span objects.
bool ResourceParser::FlattenXmlSubtree(
- xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string,
+ xml::XmlPullParser* parser, std::string* out_raw_string, android::StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections) {
std::string raw_string;
std::string current_text;
@@ -308,7 +305,7 @@ bool ResourceParser::FlattenXmlSubtree(
// Check that an 'untranslatable' tag is not already being processed. Nested
// <xliff:g> tags are illegal.
if (untranslatable_start_depth) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "illegal nested XLIFF 'g' tag");
return false;
} else {
@@ -323,7 +320,7 @@ bool ResourceParser::FlattenXmlSubtree(
}
} else {
// Besides XLIFF, any other namespaced tag is unsupported and ignored.
- diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Warn(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "ignoring element '" << parser->element_name()
<< "' with unknown namespace '" << parser->element_namespace() << "'");
node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
@@ -383,7 +380,8 @@ bool ResourceParser::FlattenXmlSubtree(
StringBuilder builder;
root.Build(&builder);
if (!builder) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) << builder.GetError());
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+ << builder.GetError());
return false;
}
@@ -405,7 +403,7 @@ bool ResourceParser::Parse(xml::XmlPullParser* parser) {
}
if (!parser->element_namespace().empty() || parser->element_name() != "resources") {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "root element must be <resources>");
return false;
}
@@ -415,7 +413,7 @@ bool ResourceParser::Parse(xml::XmlPullParser* parser) {
};
if (parser->event() == xml::XmlPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "xml parser error: " << parser->error());
return false;
}
@@ -437,7 +435,7 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) {
if (event == xml::XmlPullParser::Event::kText) {
if (!util::TrimWhitespace(parser->text()).empty()) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "plain text not allowed here");
error = true;
}
@@ -486,8 +484,9 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) {
for (const ResourceName& stripped_resource : stripped_resources) {
if (!table_->FindResource(stripped_resource)) {
// Failed to find the resource.
- diag_->Error(DiagMessage(source_) << "resource '" << stripped_resource
- << "' was filtered out but no product variant remains");
+ diag_->Error(android::DiagMessage(source_)
+ << "resource '" << stripped_resource
+ << "' was filtered out but no product variant remains");
error = true;
}
}
@@ -562,7 +561,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
resource_type = maybe_type.value().to_string();
} else {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "<item> must have a 'type' attribute");
return false;
}
@@ -573,9 +572,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// overridden.
resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value());
if (!resource_format) {
- diag_->Error(DiagMessage(out_resource->source)
- << "'" << maybe_format.value()
- << "' is an invalid format");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "'" << maybe_format.value() << "' is an invalid format");
return false;
}
}
@@ -586,7 +584,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
resource_type = maybe_type.value().to_string();
} else {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "<bag> must have a 'type' attribute");
return false;
}
@@ -598,9 +596,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (resource_type == "id") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
@@ -626,9 +623,9 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
out_resource->value = util::make_unique<Id>();
} else if (!ref || ref->name.value().type.type != ResourceType::kId) {
// If an inner element exists, the inner element must be a reference to another resource id
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> inner element must either be a resource reference or empty");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name()
+ << "> inner element must either be a resource reference or empty");
return false;
}
}
@@ -636,7 +633,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
return true;
} else if (resource_type == "macro") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
@@ -653,7 +650,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// This is an item, record its type and format and start parsing.
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
@@ -682,7 +679,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (resource_type != kPublicGroupTag && resource_type != kStagingPublicGroupTag &&
resource_type != kStagingPublicGroupFinalTag && resource_type != "overlayable") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
@@ -705,9 +702,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(resource_type);
if (parsed_type) {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
@@ -715,7 +711,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
out_resource->name.entry = maybe_name.value().to_string();
out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for type '" << *parsed_type << "'. Expected a reference");
return false;
}
@@ -724,8 +720,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
}
// If the resource type was not recognized, write the error and return false.
- diag_->Error(DiagMessage(out_resource->source)
- << "unknown resource type '" << resource_type << "'");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "unknown resource type '" << resource_type << "'");
return false;
}
@@ -738,8 +734,8 @@ bool ResourceParser::ParseItem(xml::XmlPullParser* parser,
out_resource->value = ParseXml(parser, format, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid "
- << out_resource->name.type);
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "invalid " << out_resource->name.type);
return false;
}
return true;
@@ -750,7 +746,7 @@ std::optional<FlattenedXmlSubTree> ResourceParser::CreateFlattenSubTree(
const size_t begin_xml_line = parser->line_number();
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
if (!FlattenXmlSubtree(parser, &raw_value, &style_string, &untranslatable_sections)) {
return {};
@@ -783,13 +779,13 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
const uint32_t type_mask, const bool allow_raw_value,
ResourceTable& table,
const android::ConfigDescription& config,
- IDiagnostics& diag) {
+ android::IDiagnostics& diag) {
if (!xmlsub_tree.style_string.spans.empty()) {
// This can only be a StyledString.
std::unique_ptr<StyledString> styled_string =
util::make_unique<StyledString>(table.string_pool.MakeRef(
xmlsub_tree.style_string,
- StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
styled_string->untranslatable_sections = xmlsub_tree.untranslatable_sections;
return std::move(styled_string);
}
@@ -817,8 +813,8 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
// Try making a regular string.
if (type_mask & android::ResTable_map::TYPE_STRING) {
// Use the trimmed, escaped string.
- std::unique_ptr<String> string = util::make_unique<String>(
- table.string_pool.MakeRef(xmlsub_tree.style_string.str, StringPool::Context(config)));
+ std::unique_ptr<String> string = util::make_unique<String>(table.string_pool.MakeRef(
+ xmlsub_tree.style_string.str, android::StringPool::Context(config)));
string->untranslatable_sections = xmlsub_tree.untranslatable_sections;
return std::move(string);
}
@@ -826,7 +822,7 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
if (allow_raw_value) {
// We can't parse this so return a RawString if we are allowed.
return util::make_unique<RawString>(table.string_pool.MakeRef(
- util::TrimWhitespace(xmlsub_tree.raw_value), StringPool::Context(config)));
+ util::TrimWhitespace(xmlsub_tree.raw_value), android::StringPool::Context(config)));
} else if (util::TrimWhitespace(xmlsub_tree.raw_value).empty()) {
// If the text is empty, and the value is not allowed to be a string, encode it as a @null.
return ResourceUtils::MakeNull();
@@ -840,7 +836,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (std::optional<StringPiece> formatted_attr = xml::FindAttribute(parser, "formatted")) {
std::optional<bool> maybe_formatted = ResourceUtils::ParseBool(formatted_attr.value());
if (!maybe_formatted) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'formatted'. Must be a boolean");
return false;
}
@@ -851,7 +847,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
if (!maybe_translatable) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -861,7 +857,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
out_resource->value =
ParseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source) << "not a valid string");
+ diag_->Error(android::DiagMessage(out_resource->source) << "not a valid string");
return false;
}
@@ -870,7 +866,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (formatted && translatable) {
if (!util::VerifyJavaStringFormat(*string_value->value)) {
- DiagMessage msg(out_resource->source);
+ android::DiagMessage msg(out_resource->source);
msg << "multiple substitutions specified in non-positional format; "
"did you mean to add the formatted=\"false\" attribute?";
if (options_.error_on_positional_arguments) {
@@ -895,7 +891,7 @@ bool ResourceParser::ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<macro> tags cannot be declared in configurations other than the default "
"configuration'");
return false;
@@ -919,28 +915,27 @@ bool ResourceParser::ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_
bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<public> tag not allowed with --visibility flag");
return false;
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
+ diag_->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <public> tag");
}
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<public> must have a 'type' attribute");
return false;
}
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
if (!parsed_type) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '"
- << maybe_type.value()
- << "' in <public>");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value() << "' in <public>");
return false;
}
@@ -949,7 +944,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out
if (std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) {
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
if (!maybe_id) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid resource ID '" << maybe_id_str.value() << "' in <public>");
return false;
}
@@ -967,37 +962,39 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out
template <typename Func>
bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resource,
- const char* tag_name, IDiagnostics* diag, Func&& func) {
+ const char* tag_name, android::IDiagnostics* diag, Func&& func) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag->Warn(DiagMessage(out_resource->source)
+ diag->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <" << tag_name
<< "> tag");
}
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "<" << tag_name << "> must have a 'type' attribute");
return false;
}
- std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
- if (!parsed_type) {
- diag->Error(DiagMessage(out_resource->source)
+ std::optional<ResourceNamedTypeRef> maybe_parsed_type =
+ ParseResourceNamedType(maybe_type.value());
+ if (!maybe_parsed_type) {
+ diag->Error(android::DiagMessage(out_resource->source)
<< "invalid resource type '" << maybe_type.value() << "' in <" << tag_name << ">");
return false;
}
+ auto parsed_type = maybe_parsed_type->ToResourceNamedType();
std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id");
if (!maybe_id_str) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "<" << tag_name << "> must have a 'first-id' attribute");
return false;
}
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
if (!maybe_id) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "invalid resource ID '" << maybe_id_str.value() << "' in <" << tag_name << ">");
return false;
}
@@ -1015,25 +1012,27 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
continue;
}
- const Source item_source = out_resource->source.WithLine(parser->line_number());
+ const android::Source item_source = out_resource->source.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "public") {
auto maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag->Error(DiagMessage(item_source) << "<public> must have a 'name' attribute");
+ diag->Error(android::DiagMessage(item_source) << "<public> must have a 'name' attribute");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "id")) {
- diag->Error(DiagMessage(item_source) << "'id' is ignored within <" << tag_name << ">");
+ diag->Error(android::DiagMessage(item_source)
+ << "'id' is ignored within <" << tag_name << ">");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "type")) {
- diag->Error(DiagMessage(item_source) << "'type' is ignored within <" << tag_name << ">");
+ diag->Error(android::DiagMessage(item_source)
+ << "'type' is ignored within <" << tag_name << ">");
error = true;
continue;
}
@@ -1046,7 +1045,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
}
ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
- .name = ResourceName{{}, *parsed_type, maybe_name.value().to_string()},
+ .name = ResourceName{{}, parsed_type, maybe_name.value().to_string()},
.source = item_source,
.comment = std::move(comment),
});
@@ -1057,7 +1056,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
next_id.id++;
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag->Error(android::DiagMessage(item_source) << ":" << element_name << ">");
error = true;
}
}
@@ -1084,7 +1083,7 @@ bool ResourceParser::ParseStagingPublicGroupFinal(xml::XmlPullParser* parser,
bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << kPublicGroupTag << "> tag not allowed with --visibility flag");
return false;
}
@@ -1100,15 +1099,14 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
ParsedResource* out_resource) {
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> must have a 'type' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> must have a 'type' attribute");
return false;
}
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
if (!parsed_type) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid resource type '" << maybe_type.value() << "' in <"
<< parser->element_name() << ">");
return false;
@@ -1120,12 +1118,12 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<java-symbol> and <symbol> tags not allowed with --visibility flag");
return false;
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
+ diag_->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <"
<< parser->element_name() << "> tag");
}
@@ -1140,15 +1138,14 @@ bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out
bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for <overlayable> tag");
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
}
std::optional<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
if (!overlayable_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<overlayable> tag must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<overlayable> tag must have a 'name' attribute");
return false;
}
@@ -1156,7 +1153,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
android::base::StringPrintf("%s://", Overlayable::kActorScheme);
std::optional<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "specified <overlayable> tag 'actor' attribute must use the scheme '"
<< Overlayable::kActorScheme << "'");
return false;
@@ -1190,13 +1187,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
continue;
}
- const Source element_source = source_.WithLine(parser->line_number());
+ const android::Source element_source = source_.WithLine(parser->line_number());
const std::string& element_name = parser->element_name();
const std::string& element_namespace = parser->element_namespace();
if (element_namespace.empty() && element_name == "item") {
if (current_policies == PolicyFlags::NONE) {
- diag_->Error(DiagMessage(element_source)
- << "<item> within an <overlayable> must be inside a <policy> block");
+ diag_->Error(android::DiagMessage(element_source)
+ << "<item> within an <overlayable> must be inside a <policy> block");
error = true;
continue;
}
@@ -1204,7 +1201,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
// Items specify the name and type of resource that should be overlayable
std::optional<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
if (!item_name) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'name' attribute");
error = true;
continue;
@@ -1212,7 +1209,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
std::optional<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
if (!item_type) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'type' attribute");
error = true;
continue;
@@ -1220,7 +1217,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
std::optional<ResourceNamedTypeRef> type = ParseResourceNamedType(item_type.value());
if (!type) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "invalid resource type '" << item_type.value()
<< "' in <item> within an <overlayable>");
error = true;
@@ -1241,7 +1238,8 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
} else if (element_namespace.empty() && element_name == "policy") {
if (current_policies != PolicyFlags::NONE) {
// If the policy list is not empty, then we are currently inside a policy element
- diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
+ diag_->Error(android::DiagMessage(element_source)
+ << "<policy> blocks cannot be recursively nested");
error = true;
break;
} else if (std::optional<StringPiece> maybe_type =
@@ -1256,7 +1254,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
return trimmed_part == it.first;
});
if (policy == kPolicyStringToFlag.end()) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<policy> has unsupported type '" << trimmed_part << "'");
error = true;
continue;
@@ -1265,14 +1263,15 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
current_policies |= policy->second;
}
} else {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<policy> must have a 'type' attribute");
error = true;
continue;
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
- << " in <overlayable>");
+ diag_->Error(android::DiagMessage(element_source)
+ << "invalid element <" << element_name << "> "
+ << " in <overlayable>");
error = true;
break;
}
@@ -1304,9 +1303,9 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
// Attributes only end up in default configuration.
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for attribute " << out_resource->name);
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for attribute "
+ << out_resource->name);
out_resource->config = ConfigDescription::DefaultConfig();
}
@@ -1316,7 +1315,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (maybe_format) {
type_mask = ParseFormatAttribute(maybe_format.value());
if (type_mask == 0) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid attribute format '" << maybe_format.value() << "'");
return false;
}
@@ -1327,7 +1326,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) {
StringPiece min_str = util::TrimWhitespace(maybe_min_str.value());
if (!min_str.empty()) {
- std::u16string min_str16 = util::Utf8ToUtf16(min_str);
+ std::u16string min_str16 = android::util::Utf8ToUtf16(min_str);
android::Res_value value;
if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(), &value)) {
maybe_min = static_cast<int32_t>(value.data);
@@ -1335,7 +1334,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
}
if (!maybe_min) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid 'min' value '" << min_str << "'");
return false;
}
@@ -1344,7 +1343,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) {
StringPiece max_str = util::TrimWhitespace(maybe_max_str.value());
if (!max_str.empty()) {
- std::u16string max_str16 = util::Utf8ToUtf16(max_str);
+ std::u16string max_str16 = android::util::Utf8ToUtf16(max_str);
android::Res_value value;
if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(), &value)) {
maybe_max = static_cast<int32_t>(value.data);
@@ -1352,7 +1351,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
}
if (!maybe_max) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid 'max' value '" << max_str << "'");
return false;
}
@@ -1360,7 +1359,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if ((maybe_min || maybe_max) &&
(type_mask & android::ResTable_map::TYPE_INTEGER) == 0) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "'min' and 'max' can only be used when format='integer'");
return false;
}
@@ -1385,13 +1384,13 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && (element_name == "flag" || element_name == "enum")) {
if (element_name == "enum") {
if (type_mask & android::ResTable_map::TYPE_FLAGS) {
- diag_->Error(DiagMessage(item_source)
+ diag_->Error(android::DiagMessage(item_source)
<< "can not define an <enum>; already defined a <flag>");
error = true;
continue;
@@ -1400,7 +1399,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
} else if (element_name == "flag") {
if (type_mask & android::ResTable_map::TYPE_ENUM) {
- diag_->Error(DiagMessage(item_source)
+ diag_->Error(android::DiagMessage(item_source)
<< "can not define a <flag>; already defined an <enum>");
error = true;
continue;
@@ -1425,11 +1424,10 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
auto insert_result = items.insert(std::move(symbol));
if (!insert_result.second) {
const Attribute::Symbol& existing_symbol = *insert_result.first;
- diag_->Error(DiagMessage(item_source)
- << "duplicate symbol '"
- << existing_symbol.symbol.name.value().entry << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "duplicate symbol '" << existing_symbol.symbol.name.value().entry << "'");
- diag_->Note(DiagMessage(existing_symbol.symbol.GetSource())
+ diag_->Note(android::DiagMessage(existing_symbol.symbol.GetSource())
<< "first defined here");
error = true;
}
@@ -1437,7 +1435,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
error = true;
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source) << ":" << element_name << ">");
error = true;
}
@@ -1460,28 +1458,27 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPullParser* parser,
const StringPiece& tag) {
- const Source source = source_.WithLine(parser->line_number());
+ const android::Source source = source_.WithLine(parser->line_number());
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(source) << "no attribute 'name' found for tag <"
- << tag << ">");
+ diag_->Error(android::DiagMessage(source)
+ << "no attribute 'name' found for tag <" << tag << ">");
return {};
}
std::optional<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value");
if (!maybe_value) {
- diag_->Error(DiagMessage(source) << "no attribute 'value' found for tag <"
- << tag << ">");
+ diag_->Error(android::DiagMessage(source)
+ << "no attribute 'value' found for tag <" << tag << ">");
return {};
}
- std::u16string value16 = util::Utf8ToUtf16(maybe_value.value());
+ std::u16string value16 = android::util::Utf8ToUtf16(maybe_value.value());
android::Res_value val;
if (!android::ResTable::stringToInt(value16.data(), value16.size(), &val)) {
- diag_->Error(DiagMessage(source) << "invalid value '" << maybe_value.value()
- << "' for <" << tag
- << ">; must be an integer");
+ diag_->Error(android::DiagMessage(source) << "invalid value '" << maybe_value.value()
+ << "' for <" << tag << ">; must be an integer");
return {};
}
@@ -1492,17 +1489,18 @@ std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPul
}
bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
- const Source source = source_.WithLine(parser->line_number());
+ const android::Source source = source_.WithLine(parser->line_number());
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(source) << "<item> must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(source) << "<item> must have a 'name' attribute");
return false;
}
std::optional<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_key) {
- diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
+ diag_->Error(android::DiagMessage(source)
+ << "invalid attribute name '" << maybe_name.value() << "'");
return false;
}
@@ -1511,7 +1509,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString);
if (!value) {
- diag_->Error(DiagMessage(source) << "could not parse style item");
+ diag_->Error(android::DiagMessage(source) << "could not parse style item");
return false;
}
@@ -1532,7 +1530,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
std::string err_str;
style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str);
if (!style->parent) {
- diag_->Error(DiagMessage(out_resource->source) << err_str);
+ diag_->Error(android::DiagMessage(out_resource->source) << err_str);
return false;
}
@@ -1566,7 +1564,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
error |= !ParseStyleItem(parser, style.get());
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< ":" << element_name << ">");
error = true;
}
@@ -1585,7 +1583,7 @@ bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_
if (std::optional<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
if (resource_format == 0u) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "'" << format_attr.value() << "' is an invalid format");
return false;
}
@@ -1613,7 +1611,7 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
if (!maybe_translatable) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -1629,13 +1627,13 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "item") {
std::unique_ptr<Item> item = ParseXml(parser, typeMask, kNoRawString);
if (!item) {
- diag_->Error(DiagMessage(item_source) << "could not parse array item");
+ diag_->Error(android::DiagMessage(item_source) << "could not parse array item");
error = true;
continue;
}
@@ -1643,9 +1641,8 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
array->elements.emplace_back(std::move(item));
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "unknown tag <" << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
}
@@ -1673,15 +1670,14 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "item") {
std::optional<StringPiece> maybe_quantity = xml::FindNonEmptyAttribute(parser, "quantity");
if (!maybe_quantity) {
- diag_->Error(DiagMessage(item_source)
- << "<item> in <plurals> requires attribute "
- << "'quantity'");
+ diag_->Error(android::DiagMessage(item_source) << "<item> in <plurals> requires attribute "
+ << "'quantity'");
error = true;
continue;
}
@@ -1702,16 +1698,16 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
} else if (trimmed_quantity == "other") {
index = Plural::Other;
} else {
- diag_->Error(DiagMessage(item_source)
- << "<item> in <plural> has invalid value '"
- << trimmed_quantity << "' for attribute 'quantity'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<item> in <plural> has invalid value '" << trimmed_quantity
+ << "' for attribute 'quantity'");
error = true;
continue;
}
if (plural->values[index]) {
- diag_->Error(DiagMessage(item_source) << "duplicate quantity '"
- << trimmed_quantity << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "duplicate quantity '" << trimmed_quantity << "'");
error = true;
continue;
}
@@ -1725,9 +1721,8 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
plural->values[index]->SetSource(item_source);
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << "unknown tag <"
- << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source)
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
}
@@ -1756,9 +1751,9 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
// Declare-styleable only ends up in default config;
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for styleable " << out_resource->name.entry);
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for styleable "
+ << out_resource->name.entry);
out_resource->config = ConfigDescription::DefaultConfig();
}
@@ -1776,13 +1771,14 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "attr") {
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<attr> tag must have a 'name' attribute");
error = true;
continue;
}
@@ -1792,8 +1788,8 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
// Eg. <attr name="android:text" />
std::optional<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_ref) {
- diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '"
- << maybe_name.value() << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<attr> tag has invalid name '" << maybe_name.value() << "'");
error = true;
continue;
}
@@ -1831,9 +1827,8 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << "unknown tag <"
- << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source)
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 548f5f9531fd..396ce9767fe9 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -20,14 +20,13 @@
#include <memory>
#include <optional>
+#include "ResourceTable.h"
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
-#include "ResourceTable.h"
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
#include "xml/XmlPullParser.h"
namespace aapt {
@@ -59,10 +58,10 @@ struct ResourceParserOptions {
struct FlattenedXmlSubTree {
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
xml::IPackageDeclStack* namespace_resolver;
- Source source;
+ android::Source source;
};
/*
@@ -70,7 +69,7 @@ struct FlattenedXmlSubTree {
*/
class ResourceParser {
public:
- ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
+ ResourceParser(android::IDiagnostics* diag, ResourceTable* table, const android::Source& source,
const android::ConfigDescription& config,
const ResourceParserOptions& options = {});
bool Parse(xml::XmlPullParser* parser);
@@ -78,7 +77,7 @@ class ResourceParser {
static std::unique_ptr<Item> ParseXml(const FlattenedXmlSubTree& xmlsub_tree, uint32_t type_mask,
bool allow_raw_value, ResourceTable& table,
const android::ConfigDescription& config,
- IDiagnostics& diag);
+ android::IDiagnostics& diag);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceParser);
@@ -93,7 +92,7 @@ class ResourceParser {
// `out_untranslatable_sections` contains the sections of the string that should not be
// translated.
bool FlattenXmlSubtree(xml::XmlPullParser* parser, std::string* out_raw_string,
- StyleString* out_style_string,
+ android::StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections);
/*
@@ -133,9 +132,9 @@ class ResourceParser {
bool ParseArrayImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, uint32_t typeMask);
bool ParsePlural(xml::XmlPullParser* parser, ParsedResource* out_resource);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
ResourceTable* table_;
- Source source_;
+ android::Source source_;
android::ConfigDescription config_;
ResourceParserOptions options_;
};
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 556ffa221db5..fe7eb96ffe16 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -50,7 +50,7 @@ constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
TEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
ResourceTable table;
- ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
+ ResourceParser parser(context->GetDiagnostics(), &table, android::Source{"test"}, {});
std::string input = kXmlPreamble;
input += R"(<attr name="foo"/>)";
@@ -71,7 +71,7 @@ class ResourceParserTest : public ::testing::Test {
::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
ResourceParserOptions parserOptions;
- ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config,
+ ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"}, config,
parserOptions);
std::string input = kXmlPreamble;
@@ -711,7 +711,7 @@ TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) {
</declare-styleable>
<public type="styleable" name="bar" />
</resources>)");
- ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
+ ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"},
ConfigDescription::DefaultConfig(),
ResourceParserOptions{.preserve_visibility_of_styleables = true});
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 98cce268e213..cb4811445ed1 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -43,8 +43,9 @@ namespace aapt {
const char* Overlayable::kActorScheme = "overlay";
namespace {
-bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
- return lhs->type < rhs;
+bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs,
+ const ResourceNamedTypeRef& rhs) {
+ return lhs->named_type < rhs;
}
template <typename T>
@@ -115,18 +116,24 @@ ResourceTablePackage* ResourceTable::FindOrCreatePackage(const android::StringPi
}
template <typename Func, typename Elements>
-static ResourceTableType* FindTypeRunAction(ResourceType type, Elements& entries, Func action) {
+static ResourceTableType* FindTypeRunAction(const ResourceNamedTypeRef& type, Elements& entries,
+ Func action) {
const auto iter = std::lower_bound(entries.begin(), entries.end(), type, less_than_type);
- const bool found = iter != entries.end() && type == (*iter)->type;
+ const bool found = iter != entries.end() && type == (*iter)->named_type;
return action(found, iter);
}
-ResourceTableType* ResourceTablePackage::FindType(ResourceType type) const {
+ResourceTableType* ResourceTablePackage::FindTypeWithDefaultName(const ResourceType type) const {
+ auto named_type = ResourceNamedTypeWithDefaultName(type);
+ return FindType(named_type);
+}
+
+ResourceTableType* ResourceTablePackage::FindType(const ResourceNamedTypeRef& type) const {
return FindTypeRunAction(type, types,
[&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
}
-ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
+ResourceTableType* ResourceTablePackage::FindOrCreateType(const ResourceNamedTypeRef& type) {
return FindTypeRunAction(type, types, [&](bool found, auto& iter) {
return found ? iter->get() : types.emplace(iter, new ResourceTableType(type))->get();
});
@@ -329,7 +336,7 @@ struct PackageViewComparer {
struct TypeViewComparer {
bool operator()(const ResourceTableTypeView& lhs, const ResourceTableTypeView& rhs) {
- return lhs.id != rhs.id ? lhs.id < rhs.id : lhs.type < rhs.type;
+ return lhs.id != rhs.id ? lhs.id < rhs.id : lhs.named_type < rhs.named_type;
}
};
@@ -355,7 +362,8 @@ void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePacka
id ? id.value().package_id() : std::optional<uint8_t>{}};
auto view_package = package_inserter.Insert(table.packages, std::move(new_package));
- ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : std::optional<uint8_t>{}};
+ ResourceTableTypeView new_type{type->named_type,
+ id ? id.value().type_id() : std::optional<uint8_t>{}};
auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
if (visibility.level == Visibility::Level::kPublic) {
@@ -420,13 +428,14 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
// we can reuse those packages for other types that need to be extracted from this package.
// `start_index` is the index of the first newly created package that can be reused.
const size_t start_index = new_packages.size();
- std::map<ResourceType, size_t> type_new_package_index;
+ std::map<ResourceNamedType, size_t> type_new_package_index;
for (auto type_it = package.types.begin(); type_it != package.types.end();) {
auto& type = *type_it;
- auto type_index_iter = type_new_package_index.find(type.type);
+ auto type_index_iter = type_new_package_index.find(type.named_type);
if (type_index_iter == type_new_package_index.end()) {
// First occurrence of the resource type in this package. Keep it in this package.
- type_new_package_index.insert(type_index_iter, std::make_pair(type.type, start_index));
+ type_new_package_index.insert(type_index_iter,
+ std::make_pair(type.named_type, start_index));
++type_it;
continue;
}
@@ -440,7 +449,7 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
// Move the type into a new package
auto& other_package = new_packages[index];
- type_new_package_index[type.type] = index + 1;
+ type_new_package_index[type.named_type] = index + 1;
type_inserter.Insert(other_package.types, std::move(type));
type_it = package.types.erase(type_it);
}
@@ -455,25 +464,26 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
return view;
}
-bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
+bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) {
CHECK(diag != nullptr) << "Diagnostic pointer is null";
const bool validate = validation_ == Validation::kEnabled;
- const Source source = res.value ? res.value->GetSource() : Source{};
+ const android::Source source = res.value ? res.value->GetSource() : android::Source{};
if (validate && !res.allow_mangled && !IsValidResourceEntryName(res.name.entry)) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "resource '" << res.name << "' has invalid entry name '" << res.name.entry);
return false;
}
if (res.id.has_value() && !res.id->first.is_valid()) {
- diag->Error(DiagMessage(source) << "trying to add resource '" << res.name << "' with ID "
- << res.id->first << " but that ID is invalid");
+ diag->Error(android::DiagMessage(source)
+ << "trying to add resource '" << res.name << "' with ID " << res.id->first
+ << " but that ID is invalid");
return false;
}
auto package = FindOrCreatePackage(res.name.package);
- auto type = package->FindOrCreateType(res.name.type.type);
+ auto type = package->FindOrCreateType(res.name.type);
auto entry_it = std::equal_range(type->entries.begin(), type->entries.end(), res.name.entry,
NameEqualRange<ResourceEntry>{});
const size_t entry_count = std::distance(entry_it.first, entry_it.second);
@@ -504,7 +514,7 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
if (res.id.has_value()) {
if (entry->id && entry->id.value() != res.id->first) {
if (res.id->second != OnIdConflict::CREATE_ENTRY) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "trying to add resource '" << res.name << "' with ID " << res.id->first
<< " but resource already has ID " << entry->id.value());
return false;
@@ -532,9 +542,9 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
if (res.overlayable.has_value()) {
if (entry->overlayable_item) {
- diag->Error(DiagMessage(res.overlayable->source)
+ diag->Error(android::DiagMessage(res.overlayable->source)
<< "duplicate overlayable declaration for resource '" << res.name << "'");
- diag->Error(DiagMessage(entry->overlayable_item.value().source)
+ diag->Error(android::DiagMessage(entry->overlayable_item.value().source)
<< "previous declaration here");
return false;
}
@@ -572,9 +582,10 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
break;
case CollisionResult::kConflict:
- diag->Error(DiagMessage(source) << "duplicate value for resource '" << res.name << "' "
- << "with config '" << res.config << "'");
- diag->Error(DiagMessage(source) << "resource previously defined here");
+ diag->Error(android::DiagMessage(source)
+ << "duplicate value for resource '" << res.name << "' "
+ << "with config '" << res.config << "'");
+ diag->Error(android::DiagMessage(source) << "resource previously defined here");
return false;
case CollisionResult::kKeepOriginal:
@@ -593,7 +604,7 @@ std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -612,7 +623,7 @@ std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(const Res
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -633,7 +644,7 @@ bool ResourceTable::RemoveResource(const ResourceNameRef& name, ResourceId id) c
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -655,7 +666,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
for (const auto& pkg : packages) {
ResourceTablePackage* new_pkg = new_table->FindOrCreatePackage(pkg->name);
for (const auto& type : pkg->types) {
- ResourceTableType* new_type = new_pkg->FindOrCreateType(type->type);
+ ResourceTableType* new_type = new_pkg->FindOrCreateType(type->named_type);
new_type->visibility_level = type->visibility_level;
for (const auto& entry : type->entries) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 2e17659b0679..f49ce8147f71 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -17,17 +17,6 @@
#ifndef AAPT_RESOURCE_TABLE_H
#define AAPT_RESOURCE_TABLE_H
-#include "Diagnostics.h"
-#include "Resource.h"
-#include "ResourceValues.h"
-#include "Source.h"
-#include "StringPool.h"
-#include "io/File.h"
-
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/StringPiece.h"
-
#include <functional>
#include <map>
#include <memory>
@@ -36,6 +25,16 @@
#include <unordered_map>
#include <vector>
+#include "Resource.h"
+#include "ResourceValues.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
+#include "androidfw/StringPiece.h"
+#include "androidfw/StringPool.h"
+#include "io/File.h"
+
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace aapt {
@@ -49,7 +48,7 @@ struct Visibility {
};
Level level = Level::kUndefined;
- Source source;
+ android::Source source;
std::string comment;
// Indicates that the resource id may change across builds and that the public R.java identifier
@@ -60,14 +59,14 @@ struct Visibility {
// Represents <add-resource> in an overlay.
struct AllowNew {
- Source source;
+ android::Source source;
std::string comment;
};
// Represents the staged resource id of a finalized resource.
struct StagedId {
ResourceId id;
- Source source;
+ android::Source source;
};
struct Overlayable {
@@ -75,13 +74,14 @@ struct Overlayable {
Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
: name(name.to_string()), actor(actor.to_string()) {}
Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
- const Source& source)
- : name(name.to_string()), actor(actor.to_string()), source(source ){}
+ const android::Source& source)
+ : name(name.to_string()), actor(actor.to_string()), source(source) {
+ }
static const char* kActorScheme;
std::string name;
std::string actor;
- Source source;
+ android::Source source;
};
// Represents a declaration that a resource is overlayable at runtime.
@@ -91,7 +91,7 @@ struct OverlayableItem {
std::shared_ptr<Overlayable> overlayable;
PolicyFlags policies = PolicyFlags::NONE;
std::string comment;
- Source source;
+ android::Source source;
};
class ResourceConfigValue {
@@ -168,7 +168,7 @@ class ResourceEntry {
class ResourceTableType {
public:
// The logical type of resource (string, drawable, layout, etc.).
- const ResourceType type;
+ const ResourceNamedType named_type;
// Whether this type is public (and must maintain the same type ID across builds).
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -176,7 +176,9 @@ class ResourceTableType {
// List of resources for this type.
std::vector<std::unique_ptr<ResourceEntry>> entries;
- explicit ResourceTableType(const ResourceType type) : type(type) {}
+ explicit ResourceTableType(const ResourceNamedTypeRef& type)
+ : named_type(type.ToResourceNamedType()) {
+ }
ResourceEntry* CreateEntry(const android::StringPiece& name);
ResourceEntry* FindEntry(const android::StringPiece& name) const;
@@ -196,8 +198,9 @@ class ResourceTablePackage {
}
ResourceTablePackage() = default;
- ResourceTableType* FindType(ResourceType type) const;
- ResourceTableType* FindOrCreateType(ResourceType type);
+ ResourceTableType* FindTypeWithDefaultName(const ResourceType type) const;
+ ResourceTableType* FindType(const ResourceNamedTypeRef& type) const;
+ ResourceTableType* FindOrCreateType(const ResourceNamedTypeRef& type);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
@@ -217,7 +220,7 @@ struct ResourceTableEntryView {
};
struct ResourceTableTypeView {
- ResourceType type;
+ ResourceNamedType named_type;
std::optional<uint8_t> id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -297,7 +300,7 @@ class ResourceTable {
ResourceTable() = default;
explicit ResourceTable(Validation validation);
- bool AddResource(NewResource&& res, IDiagnostics* diag);
+ bool AddResource(NewResource&& res, android::IDiagnostics* diag);
// Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id
// order.
@@ -330,7 +333,7 @@ class ResourceTable {
// When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
// they decrement a refCount, which would cause invalid memory access if the pool was already
// destroyed.
- StringPool string_pool;
+ android::StringPool string_pool;
// The list of packages in this table, sorted alphabetically by package name and increasing
// package ID (missing ID being the lowest).
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index de73d2c203e4..0cf84736a081 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -15,15 +15,16 @@
*/
#include "ResourceTable.h"
-#include "Diagnostics.h"
-#include "ResourceValues.h"
-#include "test/Test.h"
-#include "util/Util.h"
#include <algorithm>
#include <ostream>
#include <string>
+#include "ResourceValues.h"
+#include "androidfw/IDiagnostics.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
using ::android::ConfigDescription;
using ::android::StringPiece;
using ::testing::Eq;
@@ -263,13 +264,13 @@ TEST(ResourceTableTest, SetAllowNew) {
TEST(ResourceTableTest, SetOverlayable) {
ResourceTable table;
- auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme",
- Source("res/values/overlayable.xml", 40));
+ auto overlayable = std::make_shared<Overlayable>(
+ "Name", "overlay://theme", android::Source("res/values/overlayable.xml", 40));
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
overlayable_item.comment = "comment";
- overlayable_item.source = Source("res/values/overlayable.xml", 42);
+ overlayable_item.source = android::Source("res/values/overlayable.xml", 42);
const ResourceName name = test::ParseNameOrDie("android:string/foo");
ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetOverlayable(overlayable_item).Build(),
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 23f6c88aad91..945f45b8a337 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -40,6 +40,23 @@ using ::android::base::StringPrintf;
namespace aapt {
namespace ResourceUtils {
+static std::optional<ResourceNamedType> ToResourceNamedType(const char16_t* type16,
+ const char* type, size_t type_len) {
+ std::optional<ResourceNamedTypeRef> parsed_type;
+ if (type16) {
+ auto converted = android::util::Utf16ToUtf8(StringPiece16(type16, type_len));
+ parsed_type = ParseResourceNamedType(converted);
+ } else if (type) {
+ parsed_type = ParseResourceNamedType(StringPiece(type, type_len));
+ } else {
+ return {};
+ }
+ if (!parsed_type) {
+ return {};
+ }
+ return parsed_type->ToResourceNamedType();
+}
+
std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name_in) {
// TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
ResourceName name_out;
@@ -47,27 +64,17 @@ std::optional<ResourceName> ToResourceName(const android::ResTable::resource_nam
return {};
}
- name_out.package =
- util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen));
-
- std::optional<ResourceNamedTypeRef> type;
- if (name_in.type) {
- type = ParseResourceNamedType(util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen)));
- } else if (name_in.type8) {
- type = ParseResourceNamedType(StringPiece(name_in.type8, name_in.typeLen));
- } else {
- return {};
- }
+ name_out.package = android::util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen));
+ std::optional<ResourceNamedType> type =
+ ToResourceNamedType(name_in.type, name_in.name8, name_in.typeLen);
if (!type) {
return {};
}
-
- name_out.type = type->ToResourceNamedType();
+ name_out.type = *type;
if (name_in.name) {
- name_out.entry =
- util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
+ name_out.entry = android::util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
} else if (name_in.name8) {
name_out.entry.assign(name_in.name8, name_in.nameLen);
} else {
@@ -84,25 +91,15 @@ std::optional<ResourceName> ToResourceName(const android::AssetManager2::Resourc
name_out.package = std::string(name_in.package, name_in.package_len);
- std::optional<ResourceNamedTypeRef> type;
- if (name_in.type16) {
- type =
- ParseResourceNamedType(util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len)));
- } else if (name_in.type) {
- type = ParseResourceNamedType(StringPiece(name_in.type, name_in.type_len));
- } else {
- return {};
- }
-
+ std::optional<ResourceNamedType> type =
+ ToResourceNamedType(name_in.type16, name_in.type, name_in.type_len);
if (!type) {
return {};
}
-
- name_out.type = type->ToResourceNamedType();
+ name_out.type = *type;
if (name_in.entry16) {
- name_out.entry =
- util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
+ name_out.entry = android::util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
} else if (name_in.entry) {
name_out.entry = std::string(name_in.entry, name_in.entry_len);
} else {
@@ -498,7 +495,7 @@ std::optional<bool> ParseBool(const StringPiece& str) {
}
std::optional<uint32_t> ParseInt(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(str);
+ std::u16string str16 = android::util::Utf8ToUtf16(str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return value.data;
@@ -509,7 +506,7 @@ std::optional<uint32_t> ParseInt(const StringPiece& str) {
std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
- std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
+ std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
if (value.dataType == android::Res_value::TYPE_INT_HEX) {
@@ -525,7 +522,7 @@ std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
std::optional<int> ParseSdkVersion(const StringPiece& str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
- std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
+ std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return static_cast<int>(value.data);
@@ -562,7 +559,7 @@ std::unique_ptr<BinaryPrimitive> MakeBool(bool val) {
}
std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
+ std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return {};
@@ -575,7 +572,7 @@ std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) {
}
std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
+ std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) {
return {};
@@ -737,7 +734,7 @@ std::string BuildResourceFileName(const ResourceFile& res_file, const NameMangle
std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const ConfigDescription& config,
const android::ResStringPool& src_pool,
const android::Res_value& res_value,
- StringPool* dst_pool) {
+ android::StringPool* dst_pool) {
if (type == ResourceType::kId) {
if (res_value.dataType != android::Res_value::TYPE_REFERENCE &&
res_value.dataType != android::Res_value::TYPE_DYNAMIC_REFERENCE) {
@@ -748,30 +745,32 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config
// fall through to regular reference deserialization logic
}
- const uint32_t data = util::DeviceToHost32(res_value.data);
+ const uint32_t data = android::util::DeviceToHost32(res_value.data);
switch (res_value.dataType) {
case android::Res_value::TYPE_STRING: {
- const std::string str = util::GetString(src_pool, data);
+ const std::string str = android::util::GetString(src_pool, data);
auto spans_result = src_pool.styleAt(data);
// Check if the string has a valid style associated with it.
if (spans_result.has_value() &&
(*spans_result)->name.index != android::ResStringPool_span::END) {
const android::ResStringPool_span* spans = spans_result->unsafe_ptr();
- StyleString style_str = {str};
+ android::StyleString style_str = {str};
while (spans->name.index != android::ResStringPool_span::END) {
- style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index),
- spans->firstChar, spans->lastChar});
+ style_str.spans.push_back(
+ android::Span{android::util::GetString(src_pool, spans->name.index), spans->firstChar,
+ spans->lastChar});
spans++;
}
return util::make_unique<StyledString>(dst_pool->MakeRef(
- style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ style_str,
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
} else {
if (type != ResourceType::kString && util::StartsWith(str, "res/")) {
// This must be a FileReference.
- std::unique_ptr<FileReference> file_ref =
- util::make_unique<FileReference>(dst_pool->MakeRef(
- str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+ std::unique_ptr<FileReference> file_ref = util::make_unique<FileReference>(
+ dst_pool->MakeRef(str, android::StringPool::Context(
+ android::StringPool::Context::kHighPriority, config)));
if (type == ResourceType::kRaw) {
file_ref->type = ResourceFile::Type::kUnknown;
} else if (util::EndsWith(*file_ref->path, ".xml")) {
@@ -783,7 +782,8 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config
}
// There are no styles associated with this string, so treat it as a simple string.
- return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config)));
+ return util::make_unique<String>(
+ dst_pool->MakeRef(str, android::StringPool::Context(config)));
}
} break;
@@ -950,7 +950,7 @@ StringBuilder::SpanHandle StringBuilder::StartSpan(const std::string& name) {
// When we start a span, all state associated with whitespace truncation and quotation is ended.
ResetTextState();
- Span span;
+ android::Span span;
span.name = name;
span.first_char = span.last_char = utf16_len_;
xml_string_.spans.push_back(std::move(span));
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index fe450a834dfa..22cf3459809d 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,15 +20,14 @@
#include <functional>
#include <memory>
+#include "NameMangler.h"
+#include "Resource.h"
+#include "ResourceValues.h"
#include "androidfw/AssetManager2.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
-
-#include "NameMangler.h"
-#include "Resource.h"
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
namespace ResourceUtils {
@@ -230,14 +229,14 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type,
const android::ConfigDescription& config,
const android::ResStringPool& src_pool,
const android::Res_value& res_value,
- StringPool* dst_pool);
+ android::StringPool* dst_pool);
// A string flattened from an XML hierarchy, which maintains tags and untranslatable sections
// in parallel data structures.
struct FlattenedXmlString {
std::string text;
std::vector<UntranslatableSection> untranslatable_sections;
- std::vector<Span> spans;
+ std::vector<android::Span> spans;
};
// Flattens an XML hierarchy into a FlattenedXmlString, formatting the text, escaping characters,
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 1aaa34deee79..568871a4d66e 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -111,7 +111,7 @@ TEST(ResourceUtilsTest, ParsePrivateReference) {
TEST(ResourceUtilsTest, ParseBinaryDynamicReference) {
android::Res_value value = {};
- value.data = util::HostToDevice32(0x01);
+ value.data = android::util::HostToDevice32(0x01);
value.dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(ResourceType::kId,
android::ConfigDescription(),
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index b796eb07f076..c4d54be01efe 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -75,7 +75,8 @@ void BaseItem<Derived>::Accept(ConstValueVisitor* visitor) const {
visitor->Visit(static_cast<const Derived*>(this));
}
-RawString::RawString(const StringPool::Ref& ref) : value(ref) {}
+RawString::RawString(const android::StringPool::Ref& ref) : value(ref) {
+}
bool RawString::Equals(const Value* value) const {
const RawString* other = ValueCast<RawString>(value);
@@ -87,7 +88,7 @@ bool RawString::Equals(const Value* value) const {
bool RawString::Flatten(android::Res_value* out_value) const {
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
@@ -136,7 +137,7 @@ bool Reference::Flatten(android::Res_value* out_value) const {
out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
}
}
- out_value->data = util::HostToDevice32(resid.id);
+ out_value->data = android::util::HostToDevice32(resid.id);
return true;
}
@@ -216,7 +217,7 @@ bool Id::Equals(const Value* value) const {
bool Id::Flatten(android::Res_value* out) const {
out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
- out->data = util::HostToDevice32(0);
+ out->data = android::util::HostToDevice32(0);
return true;
}
@@ -224,7 +225,7 @@ void Id::Print(std::ostream* out) const {
*out << "(id)";
}
-String::String(const StringPool::Ref& ref) : value(ref) {
+String::String(const android::StringPool::Ref& ref) : value(ref) {
}
bool String::Equals(const Value* value) const {
@@ -258,7 +259,7 @@ bool String::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
@@ -272,7 +273,7 @@ void String::PrettyPrint(Printer* printer) const {
printer->Print("\"");
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+StyledString::StyledString(const android::StringPool::StyleRef& ref) : value(ref) {
}
bool StyledString::Equals(const Value* value) const {
@@ -305,18 +306,18 @@ bool StyledString::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
void StyledString::Print(std::ostream* out) const {
*out << "(styled string) \"" << value->value << "\"";
- for (const StringPool::Span& span : value->spans) {
+ for (const android::StringPool::Span& span : value->spans) {
*out << " " << *span.name << ":" << span.first_char << "," << span.last_char;
}
}
-FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+FileReference::FileReference(const android::StringPool::Ref& _path) : path(_path) {
}
bool FileReference::Equals(const Value* value) const {
@@ -333,7 +334,7 @@ bool FileReference::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(path.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(path.index()));
return true;
}
@@ -373,7 +374,7 @@ bool BinaryPrimitive::Equals(const Value* value) const {
bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
out_value->dataType = value.dataType;
- out_value->data = util::HostToDevice32(value.data);
+ out_value->data = android::util::HostToDevice32(value.data);
return true;
}
@@ -678,7 +679,7 @@ void Attribute::Print(std::ostream* out) const {
}
static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& value,
- DiagMessage* out_msg) {
+ android::DiagMessage* out_msg) {
*out_msg << "expected";
if (attr.type_mask & android::ResTable_map::TYPE_BOOLEAN) {
*out_msg << " boolean";
@@ -723,7 +724,7 @@ static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& val
*out_msg << " but got " << value;
}
-bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const {
+bool Attribute::Matches(const Item& item, android::DiagMessage* out_msg) const {
constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
@@ -732,7 +733,7 @@ bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const {
android::Res_value val = {};
item.Flatten(&val);
- const uint32_t flattened_data = util::DeviceToHost32(val.data);
+ const uint32_t flattened_data = android::util::DeviceToHost32(val.data);
// Always allow references.
const uint32_t actual_type = ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType);
@@ -872,7 +873,7 @@ void Style::Print(std::ostream* out) const {
*out << " [" << util::Joiner(entries, ", ") << "]";
}
-Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
+Style::Entry CloneEntry(const Style::Entry& entry, android::StringPool* pool) {
Style::Entry cloned_entry{entry.key};
if (entry.value != nullptr) {
CloningValueTransformer cloner(pool);
@@ -881,7 +882,7 @@ Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
return cloned_entry;
}
-void Style::MergeWith(Style* other, StringPool* pool) {
+void Style::MergeWith(Style* other, android::StringPool* pool) {
if (other->parent) {
parent = other->parent;
}
@@ -1077,7 +1078,7 @@ std::unique_ptr<T> CopyValueFields(std::unique_ptr<T> new_value, const T* value)
return new_value;
}
-CloningValueTransformer::CloningValueTransformer(StringPool* new_pool)
+CloningValueTransformer::CloningValueTransformer(android::StringPool* new_pool)
: ValueTransformer(new_pool) {
}
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 1694d6b6fe4a..f5167a1ac8e6 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -22,13 +22,12 @@
#include <ostream>
#include <vector>
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
#include "Resource.h"
-#include "StringPool.h"
#include "ValueTransformer.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+#include "androidfw/StringPool.h"
#include "io/File.h"
#include "text/Printer.h"
@@ -67,15 +66,15 @@ class Value {
}
// Returns the source where this value was defined.
- const Source& GetSource() const {
+ const android::Source& GetSource() const {
return source_;
}
- void SetSource(const Source& source) {
+ void SetSource(const android::Source& source) {
source_ = source;
}
- void SetSource(Source&& source) {
+ void SetSource(android::Source&& source) {
source_ = std::move(source);
}
@@ -113,7 +112,7 @@ class Value {
friend std::ostream& operator<<(std::ostream& out, const Value& value);
protected:
- Source source_;
+ android::Source source_;
std::string comment_;
bool weak_ = false;
bool translatable_ = true;
@@ -197,9 +196,9 @@ struct Id : public TransformableItem<Id, BaseItem<Id>> {
// A raw, unprocessed string. This may contain quotations, escape sequences, and whitespace.
// This shall *NOT* end up in the final resource table.
struct RawString : public TransformableItem<RawString, BaseItem<RawString>> {
- StringPool::Ref value;
+ android::StringPool::Ref value;
- explicit RawString(const StringPool::Ref& ref);
+ explicit RawString(const android::StringPool::Ref& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -225,14 +224,14 @@ inline bool operator!=(const UntranslatableSection& a, const UntranslatableSecti
}
struct String : public TransformableItem<String, BaseItem<String>> {
- StringPool::Ref value;
+ android::StringPool::Ref value;
// Sections of the string to NOT translate. Mainly used
// for pseudolocalization. This data is NOT persisted
// in any format.
std::vector<UntranslatableSection> untranslatable_sections;
- explicit String(const StringPool::Ref& ref);
+ explicit String(const android::StringPool::Ref& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -241,14 +240,14 @@ struct String : public TransformableItem<String, BaseItem<String>> {
};
struct StyledString : public TransformableItem<StyledString, BaseItem<StyledString>> {
- StringPool::StyleRef value;
+ android::StringPool::StyleRef value;
// Sections of the string to NOT translate. Mainly used
// for pseudolocalization. This data is NOT persisted
// in any format.
std::vector<UntranslatableSection> untranslatable_sections;
- explicit StyledString(const StringPool::StyleRef& ref);
+ explicit StyledString(const android::StringPool::StyleRef& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -256,7 +255,7 @@ struct StyledString : public TransformableItem<StyledString, BaseItem<StyledStri
};
struct FileReference : public TransformableItem<FileReference, BaseItem<FileReference>> {
- StringPool::Ref path;
+ android::StringPool::Ref path;
// A handle to the file object from which this file can be read.
// This field is NOT persisted in any format. It is transient.
@@ -267,7 +266,7 @@ struct FileReference : public TransformableItem<FileReference, BaseItem<FileRefe
ResourceFile::Type type = ResourceFile::Type::kUnknown;
FileReference() = default;
- explicit FileReference(const StringPool::Ref& path);
+ explicit FileReference(const android::StringPool::Ref& path);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -315,7 +314,7 @@ struct Attribute : public TransformableValue<Attribute, BaseValue<Attribute>> {
static std::string MaskString(uint32_t type_mask);
void Print(std::ostream* out) const override;
- bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
+ bool Matches(const Item& item, android::DiagMessage* out_msg = nullptr) const;
};
struct Style : public TransformableValue<Style, BaseValue<Style>> {
@@ -338,7 +337,7 @@ struct Style : public TransformableValue<Style, BaseValue<Style>> {
// Merges `style` into this Style. All identical attributes of `style` take precedence, including
// the parent, if there is one.
- void MergeWith(Style* style, StringPool* pool);
+ void MergeWith(Style* style, android::StringPool* pool);
};
struct Array : public TransformableValue<Array, BaseValue<Array>> {
@@ -367,7 +366,7 @@ struct Styleable : public TransformableValue<Styleable, BaseValue<Styleable>> {
struct Macro : public TransformableValue<Macro, BaseValue<Macro>> {
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
struct Namespace {
@@ -399,7 +398,7 @@ typename std::enable_if<std::is_base_of<Value, T>::value, std::ostream&>::type o
}
struct CloningValueTransformer : public ValueTransformer {
- explicit CloningValueTransformer(StringPool* new_pool);
+ explicit CloningValueTransformer(android::StringPool* new_pool);
std::unique_ptr<Reference> TransformDerived(const Reference* value) override;
std::unique_ptr<Id> TransformDerived(const Id* value) override;
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index c75a4b99e138..d788e3fd5fc7 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -37,7 +37,7 @@ constexpr const uint32_t TYPE_STRING = android::ResTable_map::TYPE_STRING;
} // namespace
TEST(ResourceValuesTest, PluralEquals) {
- StringPool pool;
+ android::StringPool pool;
Plural a;
a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
@@ -56,7 +56,7 @@ TEST(ResourceValuesTest, PluralEquals) {
}
TEST(ResourceValuesTest, PluralClone) {
- StringPool pool;
+ android::StringPool pool;
Plural a;
a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
@@ -68,7 +68,7 @@ TEST(ResourceValuesTest, PluralClone) {
}
TEST(ResourceValuesTest, ArrayEquals) {
- StringPool pool;
+ android::StringPool pool;
Array a;
a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
@@ -92,7 +92,7 @@ TEST(ResourceValuesTest, ArrayEquals) {
}
TEST(ResourceValuesTest, ArrayClone) {
- StringPool pool;
+ android::StringPool pool;
Array a;
a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
@@ -104,7 +104,7 @@ TEST(ResourceValuesTest, ArrayClone) {
}
TEST(ResourceValuesTest, StyleEquals) {
- StringPool pool;
+ android::StringPool pool;
std::unique_ptr<Style> a = test::StyleBuilder()
.SetParent("android:style/Parent")
@@ -168,10 +168,10 @@ TEST(ResourceValuesTest, StyleClone) {
}
TEST(ResourcesValuesTest, StringClones) {
- StringPool pool_a;
- StringPool pool_b;
+ android::StringPool pool_a;
+ android::StringPool pool_b;
- String str_a(pool_a.MakeRef("hello", StringPool::Context(test::ParseConfigOrDie("en"))));
+ String str_a(pool_a.MakeRef("hello", android::StringPool::Context(test::ParseConfigOrDie("en"))));
ASSERT_THAT(pool_a, SizeIs(1u));
EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
@@ -185,8 +185,8 @@ TEST(ResourcesValuesTest, StringClones) {
}
TEST(ResourceValuesTest, StyleMerges) {
- StringPool pool_a;
- StringPool pool_b;
+ android::StringPool pool_a;
+ android::StringPool pool_b;
std::unique_ptr<Style> a =
test::StyleBuilder()
@@ -204,7 +204,7 @@ TEST(ResourceValuesTest, StyleMerges) {
a->MergeWith(b.get(), &pool_a);
- StringPool pool;
+ android::StringPool pool;
std::unique_ptr<Style> expected =
test::StyleBuilder()
.SetParent("android:style/OverlayParent")
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 2c55d1d548db..01d3c84e05ba 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -135,13 +135,13 @@ TEST(ResourceTypeTest, ParseResourceNamedType) {
type = ParseResourceNamedType("layout");
EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:2");
- EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:2", ResourceType::kLayout))));
+ type = ParseResourceNamedType("layout.2");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout.2", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:another");
- EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:another", ResourceType::kLayout))));
+ type = ParseResourceNamedType("layout.another");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout.another", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:");
+ type = ParseResourceNamedType("layout.");
EXPECT_THAT(type, Eq(std::nullopt));
type = ParseResourceNamedType("layout2");
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 95b794964068..2a450ba45aeb 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -636,4 +636,4 @@ message StyleString {
message UntranslatableSection {
uint64 start_index = 1;
uint64 end_index = 2;
-} \ No newline at end of file
+}
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 8ea43abff895..34e8edb0a47f 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@ namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
static const auto sDevelopmentSdkCodeNames =
- std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu"});
+ std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},
diff --git a/tools/aapt2/ValueTransformer.h b/tools/aapt2/ValueTransformer.h
index 6fc4a191b04b..68242659dc73 100644
--- a/tools/aapt2/ValueTransformer.h
+++ b/tools/aapt2/ValueTransformer.h
@@ -19,7 +19,7 @@
#include <memory>
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
@@ -82,7 +82,7 @@ struct Macro;
struct ValueTransformer {
// `new_pool` is the new StringPool that newly created Values should use for string storing string
// values.
- explicit ValueTransformer(StringPool* new_pool);
+ explicit ValueTransformer(android::StringPool* new_pool);
virtual ~ValueTransformer() = default;
AAPT_TRANSFORM_ITEM(Id);
@@ -101,7 +101,7 @@ struct ValueTransformer {
AAPT_TRANSFORM_VALUE(Macro);
protected:
- StringPool* const pool_;
+ android::StringPool* const pool_;
};
#undef AAPT_TRANSFORM_VALUE
@@ -127,4 +127,4 @@ struct TransformableItem : public TransformableValue<Derived, Base> {
// Implementation
#include "ValueTransformer_inline.h"
-#endif // AAPT_VALUE_TRANSFORMER_H \ No newline at end of file
+#endif // AAPT_VALUE_TRANSFORMER_H
diff --git a/tools/aapt2/ValueTransformer_inline.h b/tools/aapt2/ValueTransformer_inline.h
index c6c07c0fd6f9..4f8eadca54e3 100644
--- a/tools/aapt2/ValueTransformer_inline.h
+++ b/tools/aapt2/ValueTransformer_inline.h
@@ -19,7 +19,7 @@
namespace aapt {
-inline ValueTransformer::ValueTransformer(StringPool* new_pool) : pool_(new_pool) {
+inline ValueTransformer::ValueTransformer(android::StringPool* new_pool) : pool_(new_pool) {
}
template <typename Derived, typename Base>
@@ -44,4 +44,4 @@ Item* TransformableItem<Derived, Base>::TransformItemImpl(ValueTransformer& tran
} // namespace aapt
-#endif // AAPT_VALUE_TRANSFORMER_IMPL_H \ No newline at end of file
+#endif // AAPT_VALUE_TRANSFORMER_IMPL_H
diff --git a/tools/aapt2/cmd/ApkInfo.cpp b/tools/aapt2/cmd/ApkInfo.cpp
new file mode 100644
index 000000000000..697b110443fd
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "ApkInfo.h"
+
+#include <fcntl.h>
+
+#include <iostream>
+#include <memory>
+
+#include "LoadedApk.h"
+#include "android-base/file.h" // for O_BINARY
+#include "android-base/utf8.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
+#include "dump/DumpManifest.h"
+#include "format/proto/ProtoSerialize.h"
+
+using ::android::StringPiece;
+
+namespace aapt {
+
+int ExportApkInfo(LoadedApk* apk, bool include_resource_table,
+ const std::unordered_set<std::string>& xml_resources, pb::ApkInfo* out_apk_info,
+ android::IDiagnostics* diag) {
+ auto result = DumpBadgingProto(apk, out_apk_info->mutable_badging(), diag);
+ if (result != 0) {
+ return result;
+ }
+
+ if (include_resource_table) {
+ SerializeTableToPb(*apk->GetResourceTable(), out_apk_info->mutable_resource_table(), diag);
+ }
+
+ for (auto& xml_resource : xml_resources) {
+ auto xml = apk->LoadXml(xml_resource, diag);
+ if (xml) {
+ auto out_xml = out_apk_info->add_xml_files();
+ out_xml->set_path(xml_resource);
+ SerializeXmlResourceToPb(*xml, out_xml->mutable_root(),
+ {/* remove_empty_text_nodes= */ true});
+ }
+ }
+
+ return 0;
+}
+
+int ApkInfoCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() != 1) {
+ std::cerr << "must supply a single APK\n";
+ Usage(&std::cerr);
+ return 1;
+ }
+ const StringPiece& path = args[0];
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, diag_);
+ if (!apk) {
+ return 1;
+ }
+
+ pb::ApkInfo out_apk_info;
+ int result =
+ ExportApkInfo(apk.get(), include_resource_table_, xml_resources_, &out_apk_info, diag_);
+ if (result != 0) {
+ diag_->Error(android::DiagMessage() << "Failed to serialize ApkInfo into proto.");
+ return result;
+ }
+
+ int mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+ int outfd = ::android::base::utf8::open(output_path_.c_str(), mode, 0666);
+ if (outfd == -1) {
+ diag_->Error(android::DiagMessage() << "Failed to open output file.");
+ return 1;
+ }
+
+ bool is_serialized = out_apk_info.SerializeToFileDescriptor(outfd);
+ close(outfd);
+
+ return is_serialized ? 0 : 1;
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/cmd/ApkInfo.h b/tools/aapt2/cmd/ApkInfo.h
new file mode 100644
index 000000000000..bb92a8579bc0
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#ifndef AAPT2_APKINFO_H
+#define AAPT2_APKINFO_H
+
+#include "Command.h"
+#include "androidfw/IDiagnostics.h"
+
+namespace aapt {
+
+class ApkInfoCommand : public Command {
+ public:
+ explicit ApkInfoCommand(android::IDiagnostics* diag) : Command("apkinfo"), diag_(diag) {
+ SetDescription("Dump information about an APK in binary proto format.");
+ AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath);
+ AddOptionalSwitch("--include-resource-table", "Include the resource table data into output.",
+ &include_resource_table_);
+ AddOptionalFlagList("--include-xml",
+ "Include an XML file content into output. Multiple XML files might be "
+ "requested during single invocation.",
+ &xml_resources_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ android::IDiagnostics* diag_;
+ std::string output_path_;
+ bool include_resource_table_ = false;
+ std::unordered_set<std::string> xml_resources_;
+};
+
+} // namespace aapt
+
+#endif // AAPT2_APKINFO_H
diff --git a/tools/aapt2/cmd/ApkInfo_test.cpp b/tools/aapt2/cmd/ApkInfo_test.cpp
new file mode 100644
index 000000000000..97d4abebfe6a
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "ApkInfo.h"
+
+#include "ApkInfo.pb.h"
+#include "LoadedApk.h"
+#include "android-base/unique_fd.h"
+#include "io/StringStream.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using ApkInfoTest = CommandTestFixture;
+
+void AssertProducedAndExpectedInfo(const std::string& produced_path,
+ const std::string& expected_path) {
+ android::base::unique_fd fd(open(produced_path.c_str(), O_RDONLY));
+ ASSERT_NE(fd.get(), -1);
+
+ pb::ApkInfo produced_apk_info;
+ produced_apk_info.ParseFromFileDescriptor(fd.get());
+
+ std::string expected;
+ ::android::base::ReadFileToString(expected_path, &expected);
+
+ EXPECT_EQ(produced_apk_info.DebugString(), expected);
+}
+
+static android::NoOpDiagnostics noop_diag;
+
+TEST_F(ApkInfoTest, ApkInfoWithBadging) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto out_info_path = GetTestPath("apk_info.pb");
+
+ ApkInfoCommand command(&noop_diag);
+ command.Execute({"-o", out_info_path, apk_path}, &std::cerr);
+
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_expected_proto.txt"});
+ AssertProducedAndExpectedInfo(out_info_path, expected_path);
+}
+
+TEST_F(ApkInfoTest, FullApkInfo) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto out_info_path = GetTestPath("apk_info.pb");
+
+ ApkInfoCommand command(&noop_diag);
+ command.Execute({"-o", out_info_path, "--include-resource-table", "--include-xml",
+ "AndroidManifest.xml", "--include-xml", "res/oy.xml", apk_path},
+ &std::cerr);
+
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_full_proto.txt"});
+ AssertProducedAndExpectedInfo(out_info_path, expected_path);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index fe560180bd48..0409f7391f79 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -17,19 +17,17 @@
#include "Compile.h"
#include <dirent.h>
+
#include <string>
+#include "ResourceParser.h"
+#include "ResourceTable.h"
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/utf8.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-#include "Diagnostics.h"
-#include "ResourceParser.h"
-#include "ResourceTable.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "compile/InlineXmlFormatParser.h"
@@ -39,6 +37,8 @@
#include "format/Archive.h"
#include "format/Container.h"
#include "format/proto/ProtoSerialize.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "io/BigBufferStream.h"
#include "io/FileStream.h"
#include "io/FileSystem.h"
@@ -61,7 +61,7 @@ using ::google::protobuf::io::CopyingOutputStreamAdaptor;
namespace aapt {
struct ResourcePathData {
- Source source;
+ android::Source source;
std::string resource_dir;
std::string name;
std::string extension;
@@ -122,9 +122,8 @@ static std::optional<ResourcePathData> ExtractResourcePathData(const std::string
}
}
- const Source res_path = options.source_path
- ? StringPiece(options.source_path.value())
- : StringPiece(path);
+ const android::Source res_path =
+ options.source_path ? StringPiece(options.source_path.value()) : StringPiece(path);
return ResourcePathData{res_path, dir_str.to_string(), name.to_string(),
extension.to_string(), config_str.to_string(), config};
@@ -154,8 +153,8 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
{
auto fin = file->OpenInputStream();
if (fin->HadError()) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source)
- << "failed to open file: " << fin->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file: " << fin->GetError());
return false;
}
@@ -191,7 +190,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
// Create the file/zip entry.
if (!writer->StartEntry(output_path, 0)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to open");
return false;
}
@@ -204,13 +203,13 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
pb::ResourceTable pb_table;
SerializeTableToPb(table, &pb_table, context->GetDiagnostics());
if (!container_writer.AddResTableEntry(pb_table)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to write");
return false;
}
}
if (!writer->FinishEntry()) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish entry");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to finish entry");
return false;
}
@@ -218,7 +217,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to'"
<< options.generate_text_symbols_path.value()
<< "': " << fout_text.GetError());
@@ -243,9 +242,9 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
r_txt_printer.Print("private ");
}
- if (type->type != ResourceType::kStyleable) {
+ if (type->named_type.type != ResourceType::kStyleable) {
r_txt_printer.Print("int ");
- r_txt_printer.Print(to_string(type->type));
+ r_txt_printer.Print(type->named_type.to_string());
r_txt_printer.Print(" ");
r_txt_printer.Println(entry->name);
} else {
@@ -282,11 +281,11 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const ResourceFile& file,
io::KnownSizeInputStream* in, IArchiveWriter* writer,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
TRACE_CALL();
// Start the entry so we can write the header.
if (!writer->StartEntry(output_path, 0)) {
- diag->Error(DiagMessage(output_path) << "failed to open file");
+ diag->Error(android::DiagMessage(output_path) << "failed to open file");
return false;
}
@@ -300,20 +299,20 @@ static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const Res
SerializeCompiledFileToPb(file, &pb_compiled_file);
if (!container_writer.AddResFileEntry(pb_compiled_file, in)) {
- diag->Error(DiagMessage(output_path) << "failed to write entry data");
+ diag->Error(android::DiagMessage(output_path) << "failed to write entry data");
return false;
}
}
if (!writer->FinishEntry()) {
- diag->Error(DiagMessage(output_path) << "failed to finish writing data");
+ diag->Error(android::DiagMessage(output_path) << "failed to finish writing data");
return false;
}
return true;
}
static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::XmlResource& xmlres,
- ContainerWriter* container_writer, IDiagnostics* diag) {
+ ContainerWriter* container_writer, android::IDiagnostics* diag) {
pb::internal::CompiledFile pb_compiled_file;
SerializeCompiledFileToPb(xmlres.file, &pb_compiled_file);
@@ -324,7 +323,7 @@ static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::Xml
io::StringInputStream serialized_in(serialized_xml);
if (!container_writer->AddResFileEntry(pb_compiled_file, &serialized_in)) {
- diag->Error(DiagMessage(output_path) << "failed to write entry data");
+ diag->Error(android::DiagMessage(output_path) << "failed to write entry data");
return false;
}
return true;
@@ -334,12 +333,12 @@ static bool IsValidFile(IAaptContext* context, const std::string& input_path) {
const file::FileType file_type = file::GetFileType(input_path);
if (file_type != file::FileType::kRegular && file_type != file::FileType::kSymlink) {
if (file_type == file::FileType::kDirectory) {
- context->GetDiagnostics()->Error(DiagMessage(input_path)
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path)
<< "resource file cannot be a directory");
} else if (file_type == file::FileType::kNonExistant) {
- context->GetDiagnostics()->Error(DiagMessage(input_path) << "file not found");
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path) << "file not found");
} else {
- context->GetDiagnostics()->Error(DiagMessage(input_path)
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path)
<< "not a valid resource file");
}
return false;
@@ -352,14 +351,14 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling XML");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling XML");
}
std::unique_ptr<xml::XmlResource> xmlres;
{
auto fin = file->OpenInputStream();
if (fin->HadError()) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
<< "failed to open file: " << fin->GetError());
return false;
}
@@ -389,7 +388,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
// Start the entry so we can write the header.
if (!writer->StartEntry(output_path, 0)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open file");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to open file");
return false;
}
@@ -416,7 +415,8 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
}
if (!writer->FinishEntry()) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish writing data");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path)
+ << "failed to finish writing data");
return false;
}
@@ -424,7 +424,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to'"
<< options.generate_text_symbols_path.value()
<< "': " << fout_text.GetError());
@@ -452,10 +452,10 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling PNG");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling PNG");
}
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
ResourceFile res_file;
res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
res_file.config = path_data.config;
@@ -465,11 +465,12 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
{
auto data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file ");
return false;
}
- BigBuffer crunched_png_buffer(4096);
+ android::BigBuffer crunched_png_buffer(4096);
io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
// Ensure that we only keep the chunks we care about if we end up
@@ -486,7 +487,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
std::string err;
nine_patch = NinePatch::Create(image->rows.get(), image->width, image->height, &err);
if (!nine_patch) {
- context->GetDiagnostics()->Error(DiagMessage() << err);
+ context->GetDiagnostics()->Error(android::DiagMessage() << err);
return false;
}
@@ -503,8 +504,8 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
}
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "9-patch: "
- << *nine_patch);
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
+ << "9-patch: " << *nine_patch);
}
}
@@ -522,13 +523,13 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
// The re-encoded PNG is larger than the original, and there is
// no mandatory transformation. Use the original.
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
<< "original PNG is smaller than crunched PNG"
<< ", using original");
}
png_chunk_filter.Rewind();
- BigBuffer filtered_png_buffer(4096);
+ android::BigBuffer filtered_png_buffer(4096);
io::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer);
io::Copy(&filtered_png_buffer_out, &png_chunk_filter);
buffer.AppendBuffer(std::move(filtered_png_buffer));
@@ -538,13 +539,13 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
// For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
// This will help catch exotic cases where the new code may generate larger PNGs.
std::stringstream legacy_stream(content.to_string());
- BigBuffer legacy_buffer(4096);
+ android::BigBuffer legacy_buffer(4096);
Png png(context->GetDiagnostics());
if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) {
return false;
}
- context->GetDiagnostics()->Note(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
<< "legacy=" << legacy_buffer.size()
<< " new=" << buffer.size());
}
@@ -560,7 +561,7 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling file");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling file");
}
ResourceFile res_file;
@@ -571,7 +572,8 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
auto data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file ");
return false;
}
@@ -581,7 +583,7 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
class CompileContext : public IAaptContext {
public:
- explicit CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
+ explicit CompileContext(android::IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
}
PackageType GetPackageType() override {
@@ -597,7 +599,7 @@ class CompileContext : public IAaptContext {
return verbose_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return diagnostics_;
}
@@ -633,7 +635,7 @@ class CompileContext : public IAaptContext {
private:
DISALLOW_COPY_AND_ASSIGN(CompileContext);
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
bool verbose_ = false;
};
@@ -665,7 +667,7 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
path, inputs->GetDirSeparator(), &err_str, options)) {
path_data = maybe_path_data.value();
} else {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << err_str);
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource()) << err_str);
error = true;
continue;
}
@@ -688,8 +690,8 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
}
}
} else {
- context->GetDiagnostics()->Error(DiagMessage()
- << "invalid file path '" << path_data.source << "'");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "invalid file path '" << path_data.source << "'");
error = true;
continue;
}
@@ -699,15 +701,16 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
if (compile_func != &CompileFile && !options.legacy_mode
&& std::count(path_data.name.begin(), path_data.name.end(), '.') != 0) {
error = true;
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "file name cannot contain '.' other than for"
- << " specifying the extension");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "file name cannot contain '.' other than for"
+ << " specifying the extension");
continue;
}
const std::string out_path = BuildIntermediateContainerFilename(path_data);
if (!compile_func(context, options, path_data, file, output_writer, out_path)) {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "file failed to compile");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "file failed to compile");
error = true;
}
}
@@ -728,9 +731,10 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
} else if (visibility_.value() == "default") {
options_.visibility = Visibility::Level::kUndefined;
} else {
- context.GetDiagnostics()->Error(
- DiagMessage() << "Unrecognized visibility level passes to --visibility: '"
- << visibility_.value() << "'. Accepted levels: public, private, default");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "Unrecognized visibility level passes to --visibility: '"
+ << visibility_.value()
+ << "'. Accepted levels: public, private, default");
return 1;
}
}
@@ -739,17 +743,17 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
// Collect the resources files to compile
if (options_.res_dir && options_.res_zip) {
- context.GetDiagnostics()->Error(DiagMessage()
- << "only one of --dir and --zip can be specified");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "only one of --dir and --zip can be specified");
return 1;
} else if ((options_.res_dir || options_.res_zip) &&
options_.source_path && args.size() > 1) {
- context.GetDiagnostics()->Error(DiagMessage(kPath)
- << "Cannot use an overriding source path with multiple files.");
- return 1;
+ context.GetDiagnostics()->Error(android::DiagMessage(kPath)
+ << "Cannot use an overriding source path with multiple files.");
+ return 1;
} else if (options_.res_dir) {
if (!args.empty()) {
- context.GetDiagnostics()->Error(DiagMessage() << "files given but --dir specified");
+ context.GetDiagnostics()->Error(android::DiagMessage() << "files given but --dir specified");
Usage(&std::cerr);
return 1;
}
@@ -758,12 +762,12 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
std::string err;
file_collection = io::FileCollection::Create(options_.res_dir.value(), &err);
if (!file_collection) {
- context.GetDiagnostics()->Error(DiagMessage(options_.res_dir.value()) << err);
+ context.GetDiagnostics()->Error(android::DiagMessage(options_.res_dir.value()) << err);
return 1;
}
} else if (options_.res_zip) {
if (!args.empty()) {
- context.GetDiagnostics()->Error(DiagMessage() << "files given but --zip specified");
+ context.GetDiagnostics()->Error(android::DiagMessage() << "files given but --zip specified");
Usage(&std::cerr);
return 1;
}
@@ -772,7 +776,7 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
std::string err;
file_collection = io::ZipFileCollection::Create(options_.res_zip.value(), &err);
if (!file_collection) {
- context.GetDiagnostics()->Error(DiagMessage(options_.res_zip.value()) << err);
+ context.GetDiagnostics()->Error(android::DiagMessage(options_.res_zip.value()) << err);
return 1;
}
} else {
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index bd2e3d72a551..14a730a1b1a0 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -17,15 +17,15 @@
#ifndef AAPT2_COMPILE_H
#define AAPT2_COMPILE_H
-#include <optional>
-
#include <androidfw/StringPiece.h>
-#include "format/Archive.h"
-#include "process/IResourceTableConsumer.h"
+#include <optional>
+
#include "Command.h"
-#include "Diagnostics.h"
#include "ResourceTable.h"
+#include "androidfw/IDiagnostics.h"
+#include "format/Archive.h"
+#include "process/IResourceTableConsumer.h"
namespace aapt {
@@ -47,8 +47,8 @@ struct CompileOptions {
/** Parses flags and compiles resources to be used in linking. */
class CompileCommand : public Command {
public:
- explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
- diagnostic_(diagnostic) {
+ explicit CompileCommand(android::IDiagnostics* diagnostic)
+ : Command("compile", "c"), diagnostic_(diagnostic) {
SetDescription("Compiles resources to be linked into an apk.");
AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath);
AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath);
@@ -81,7 +81,7 @@ class CompileCommand : public Command {
int Action(const std::vector<std::string>& args) override;
private:
- IDiagnostics* diagnostic_;
+ android::IDiagnostics* diagnostic_;
CompileOptions options_;
std::optional<std::string> visibility_;
std::optional<std::string> trace_folder_;
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index fbfbf68b30bb..3464a7662c60 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -219,7 +219,7 @@ static void AssertTranslations(CommandTestFixture *ctf, std::string file_name,
ASSERT_NE(table, nullptr);
table->string_pool.Sort();
- const std::vector<std::unique_ptr<StringPool::Entry>>& pool_strings =
+ const std::vector<std::unique_ptr<android::StringPool::Entry>>& pool_strings =
table->string_pool.strings();
// The actual / expected vectors have the same size
@@ -316,7 +316,7 @@ TEST_F(CompilerTest, RelativePathTest) {
std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(apk_path, &diag);
ResourceTable* resource_table = apk.get()->GetResourceTable();
- const std::vector<std::unique_ptr<StringPool::Entry>>& pool_strings =
+ const std::vector<std::unique_ptr<android::StringPool::Entry>>& pool_strings =
resource_table->string_pool.strings();
ASSERT_EQ(pool_strings.size(), 2);
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 3b097e09e09d..cf58f989a7d4 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -18,11 +18,11 @@
#include <vector>
-#include "android-base/macros.h"
-#include "androidfw/StringPiece.h"
-
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
@@ -43,8 +43,9 @@ namespace aapt {
class IApkSerializer {
public:
- IApkSerializer(IAaptContext* context, const Source& source) : context_(context),
- source_(source) {}
+ IApkSerializer(IAaptContext* context, const android::Source& source)
+ : context_(context), source_(source) {
+ }
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) = 0;
@@ -55,21 +56,22 @@ class IApkSerializer {
protected:
IAaptContext* context_;
- Source source_;
+ android::Source source_;
};
class BinaryApkSerializer : public IApkSerializer {
public:
- BinaryApkSerializer(IAaptContext* context, const Source& source,
+ BinaryApkSerializer(IAaptContext* context, const android::Source& source,
const TableFlattenerOptions& table_flattener_options,
const XmlFlattenerOptions& xml_flattener_options)
: IApkSerializer(context, source),
table_flattener_options_(table_flattener_options),
- xml_flattener_options_(xml_flattener_options) {}
+ xml_flattener_options_(xml_flattener_options) {
+ }
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) override {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
xml_flattener_options_.use_utf16 = utf16;
XmlFlattener flattener(&buffer, xml_flattener_options_);
if (!flattener.Consume(context_, xml)) {
@@ -81,7 +83,7 @@ class BinaryApkSerializer : public IApkSerializer {
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
TableFlattener table_flattener(table_flattener_options_, &buffer);
if (!table_flattener.Consume(context_, table)) {
return false;
@@ -96,7 +98,7 @@ class BinaryApkSerializer : public IApkSerializer {
if (file->type == ResourceFile::Type::kProtoXml) {
unique_ptr<io::InputStream> in = file->file->OpenInputStream();
if (in == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to open file " << *file->path);
return false;
}
@@ -104,7 +106,7 @@ class BinaryApkSerializer : public IApkSerializer {
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to parse proto XML " << *file->path);
return false;
}
@@ -112,15 +114,15 @@ class BinaryApkSerializer : public IApkSerializer {
std::string error;
unique_ptr<xml::XmlResource> xml = DeserializeXmlResourceFromPb(pb_node, &error);
if (xml == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "failed to deserialize proto XML "
- << *file->path << ": " << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
+ << "failed to deserialize proto XML " << *file->path
+ << ": " << error);
return false;
}
if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to serialize to binary XML: " << *file->path);
return false;
}
@@ -128,7 +130,7 @@ class BinaryApkSerializer : public IApkSerializer {
file->type = ResourceFile::Type::kBinaryXml;
} else {
if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to copy file " << *file->path);
return false;
}
@@ -146,8 +148,9 @@ class BinaryApkSerializer : public IApkSerializer {
class ProtoApkSerializer : public IApkSerializer {
public:
- ProtoApkSerializer(IAaptContext* context, const Source& source)
- : IApkSerializer(context, source) {}
+ ProtoApkSerializer(IAaptContext* context, const android::Source& source)
+ : IApkSerializer(context, source) {
+ }
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) override {
@@ -167,7 +170,7 @@ class ProtoApkSerializer : public IApkSerializer {
if (file->type == ResourceFile::Type::kBinaryXml) {
std::unique_ptr<io::IData> data = file->file->OpenAsData();
if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to open file " << *file->path);
return false;
}
@@ -175,14 +178,14 @@ class ProtoApkSerializer : public IApkSerializer {
std::string error;
std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
if (xml == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: "
- << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
+ << "failed to parse binary XML: " << error);
return false;
}
if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to serialize to proto XML: " << *file->path);
return false;
}
@@ -190,7 +193,7 @@ class ProtoApkSerializer : public IApkSerializer {
file->type = ResourceFile::Type::kProtoXml;
} else {
if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to copy file " << *file->path);
return false;
}
@@ -216,7 +219,7 @@ class Context : public IAaptContext {
return &symbols_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diag_;
}
@@ -240,7 +243,7 @@ class Context : public IAaptContext {
}
int GetMinSdkVersion() override {
- return 0u;
+ return min_sdk_;
}
const std::set<std::string>& GetSplitNameDependencies() override {
@@ -251,6 +254,7 @@ class Context : public IAaptContext {
bool verbose_ = false;
std::string package_;
+ int32_t min_sdk_ = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Context);
@@ -270,7 +274,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
} else if (output_format == ApkFormat::kProto) {
serializer.reset(new ProtoApkSerializer(context, apk->GetSource()));
} else {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "Cannot convert APK to unknown format");
return 1;
}
@@ -279,7 +283,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/,
output_writer, (manifest != nullptr && manifest->WasCompressed())
? ArchiveEntry::kCompress : 0u)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return 1;
}
@@ -298,7 +302,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
FileReference* file = ValueCast<FileReference>(config_value->value.get());
if (file != nullptr) {
if (file->file == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "no file associated with " << *file);
return 1;
}
@@ -306,7 +310,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
// Only serialize if we haven't seen this file before
if (files_written.insert(*file->path).second) {
if (!serializer->SerializeFile(file, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize file " << *file->path);
return 1;
}
@@ -319,7 +323,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
// Converted resource table
if (!serializer->SerializeTable(converted_table, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize the resource table");
return 1;
}
@@ -340,8 +344,8 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
}
if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to copy file " << path);
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
+ << "failed to copy file " << path);
return 1;
}
}
@@ -363,7 +367,7 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
const StringPiece& path = args[0];
unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
if (apk == nullptr) {
- context.GetDiagnostics()->Error(DiagMessage(path) << "failed to load APK");
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << "failed to load APK");
return 1;
}
@@ -373,6 +377,7 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
}
context.package_ = app_info.value().package;
+ context.min_sdk_ = app_info.value().min_sdk_version.value_or(0);
unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(context.GetDiagnostics(),
output_path_);
if (writer == nullptr) {
@@ -385,8 +390,9 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
} else if (output_format_.value() == ConvertCommand::kOutputFormatProto) {
format = ApkFormat::kProto;
} else {
- context.GetDiagnostics()->Error(DiagMessage(path) << "Invalid value for flag --output-format: "
- << output_format_.value());
+ context.GetDiagnostics()->Error(android::DiagMessage(path)
+ << "Invalid value for flag --output-format: "
+ << output_format_.value());
return 1;
}
diff --git a/tools/aapt2/cmd/Convert_test.cpp b/tools/aapt2/cmd/Convert_test.cpp
index f35237ec25e3..27df8c1b324e 100644
--- a/tools/aapt2/cmd/Convert_test.cpp
+++ b/tools/aapt2/cmd/Convert_test.cpp
@@ -101,7 +101,8 @@ TEST_F(ConvertTest, KeepRawXmlStrings) {
// Check that the raw string index has been set to the correct string pool entry
int32_t raw_index = tree.getAttributeValueStringID(0);
ASSERT_THAT(raw_index, Ne(-1));
- EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+ EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
+ Eq("007"));
}
TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index d9e8c921dbc5..423e939398d7 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -16,10 +16,10 @@
#include "Diff.h"
-#include "android-base/macros.h"
-
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
+#include "android-base/macros.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -45,7 +45,7 @@ class DiffContext : public IAaptContext {
return 0x0;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -78,7 +78,7 @@ class DiffContext : public IAaptContext {
SymbolTable symbol_table_;
};
-static void EmitDiffLine(const Source& source, const StringPiece& message) {
+static void EmitDiffLine(const android::Source& source, const StringPiece& message) {
std::cerr << source << ": " << message << "\n";
}
@@ -105,7 +105,7 @@ static bool EmitResourceConfigValueDiff(
Value* value_b = config_value_b->value.get();
if (!value_a->Equals(value_b)) {
std::stringstream str_stream;
- str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << "value " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " config=" << config_value_a->config << " does not match:\n";
value_a->Print(&str_stream);
str_stream << "\n vs \n";
@@ -128,7 +128,7 @@ static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
auto config_value_b = entry_b.FindValue(config_value_a->config);
if (!config_value_b) {
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " config=" << config_value_a->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
@@ -143,7 +143,7 @@ static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
auto config_value_a = entry_a.FindValue(config_value_b->config);
if (!config_value_a) {
std::stringstream str_stream;
- str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b.name
+ str_stream << "new config " << pkg_b.name << ":" << type_b.named_type << "/" << entry_b.name
<< " config=" << config_value_b->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
@@ -164,13 +164,15 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
if (entry_b_iter == type_b.entries.end()) {
// Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a_iter->name;
+ str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/"
+ << entry_a_iter->name;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
} else if (entry_a_iter == type_a.entries.end()) {
// Type B contains a type that type A does not have.
std::stringstream str_stream;
- str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/" << entry_b_iter->name;
+ str_stream << "new entry " << pkg_b.name << ":" << type_b.named_type << "/"
+ << entry_b_iter->name;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
@@ -178,7 +180,7 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
const auto& entry_b = *entry_b_iter;
if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " has different visibility (";
if (entry_b.visibility.staged_api) {
str_stream << "STAGED ";
@@ -203,7 +205,7 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
} else if (IsIdDiff(entry_a.visibility.level, entry_a.id, entry_b.visibility.level,
entry_b.id)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " has different public ID (";
if (entry_b.id) {
str_stream << "0x" << std::hex << entry_b.id.value();
@@ -243,13 +245,13 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
if (type_b_iter == pkg_b.types.end()) {
// Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
+ str_stream << "missing " << pkg_a.name << ":" << type_a_iter->named_type;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
} else if (type_a_iter == pkg_a.types.end()) {
// Type B contains a type that type A does not have.
std::stringstream str_stream;
- str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
+ str_stream << "new type " << pkg_b.name << ":" << type_b_iter->named_type;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
@@ -257,7 +259,7 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
const auto& type_b = *type_b_iter;
if (type_a.visibility_level != type_b.visibility_level) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << " has different visibility (";
+ str_stream << pkg_a.name << ":" << type_a.named_type << " has different visibility (";
if (type_b.visibility_level == Visibility::Level::kPublic) {
str_stream << "PUBLIC";
} else {
@@ -274,7 +276,7 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
diff = true;
} else if (IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << " has different public ID (";
+ str_stream << pkg_a.name << ":" << type_a.named_type << " has different public ID (";
if (type_b.id) {
str_stream << "0x" << std::hex << type_b.id.value();
} else {
@@ -383,7 +385,7 @@ int DiffCommand::Action(const std::vector<std::string>& args) {
return 1;
}
- IDiagnostics* diag = context.GetDiagnostics();
+ android::IDiagnostics* diag = context.GetDiagnostics();
std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
if (!apk_a || !apk_b) {
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index bcce3e5a800f..71b08022f688 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -57,8 +57,8 @@ static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
return "UNKNOWN";
}
-static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
- size_t len, Printer* printer) {
+static void DumpCompiledFile(const ResourceFile& file, const android::Source& source,
+ off64_t offset, size_t len, Printer* printer) {
printer->Print("Resource: ");
printer->Println(file.name.to_string());
@@ -83,7 +83,7 @@ class DumpContext : public IAaptContext {
return PackageType::kApp;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -138,7 +138,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
print_options.show_values = !no_values_;
if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump container specified");
+ diag_->Error(android::DiagMessage() << "No dump container specified");
return 1;
}
@@ -146,7 +146,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
for (auto container : args) {
io::FileInputStream input(container);
if (input.HadError()) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to open file: " << input.GetError());
error = true;
continue;
@@ -155,7 +155,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
// Try as a compiled file.
ContainerReader reader(&input);
if (reader.HadError()) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to read container: " << reader.GetError());
error = true;
continue;
@@ -170,7 +170,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse proto table: " << entry->GetError());
error = true;
continue;
@@ -179,7 +179,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
ResourceTable table;
error.clear();
if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse table: " << error);
error = true;
continue;
@@ -194,7 +194,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
off64_t offset;
size_t length;
if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse compiled proto file: "
<< entry->GetError());
error = true;
@@ -203,14 +203,14 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
ResourceFile file;
if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
- context.GetDiagnostics()->Warn(DiagMessage(container)
+ context.GetDiagnostics()->Warn(android::DiagMessage(container)
<< "failed to parse compiled file: " << error);
error = true;
continue;
}
printer_->Indent();
- DumpCompiledFile(file, Source(container), offset, length, printer_);
+ DumpCompiledFile(file, android::Source(container), offset, length, printer_);
printer_->Undent();
}
}
@@ -228,7 +228,7 @@ int DumpBadgerCommand::Action(const std::vector<std::string>& args) {
int DumpConfigsCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -268,13 +268,13 @@ int DumpPackageNameCommand::Dump(LoadedApk* apk) {
int DumpStringsCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
// Load the run-time xml string pool using the flattened data
- BigBuffer buffer(4096);
- StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
+ android::BigBuffer buffer(4096);
+ android::StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
auto data = buffer.to_string();
android::ResStringPool pool(data.data(), data.size(), false);
Debug::DumpResStringPool(&pool, GetPrinter());
@@ -291,14 +291,14 @@ int DumpStyleParentCommand::Dump(LoadedApk* apk) {
const auto table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
std::optional<ResourceTable::SearchResult> target = table->FindResource(target_style);
if (!target) {
- GetDiagnostics()->Error(
- DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist");
+ GetDiagnostics()->Error(android::DiagMessage()
+ << "Target style \"" << target_style.entry << "\" does not exist");
return 1;
}
@@ -315,7 +315,7 @@ int DumpTableCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -340,7 +340,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
}
// Flatten the xml document to get a binary representation of the proto xml file
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
@@ -356,7 +356,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
} else if (apk->GetApkFormat() == ApkFormat::kBinary) {
io::IFile* file = apk->GetFileCollection()->FindFile(xml_file);
if (!file) {
- GetDiagnostics()->Error(DiagMessage(xml_file)
+ GetDiagnostics()->Error(android::DiagMessage(xml_file)
<< "File '" << xml_file << "' not found in APK");
error = true;
continue;
@@ -364,7 +364,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file);
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to open " << xml_file);
error = true;
continue;
}
@@ -372,7 +372,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
// Load the run-time xml tree from the file data
tree.setTo(data->data(), data->size(), /** copyData */ true);
} else {
- GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format");
+ GetDiagnostics()->Error(android::DiagMessage(apk->GetSource()) << "Unknown APK format");
error = true;
continue;
}
@@ -396,7 +396,7 @@ int DumpXmlTreeCommand::Dump(LoadedApk* apk) {
int DumpOverlayableCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -563,13 +563,13 @@ const char DumpBadgerCommand::kBadgerData[2925] = {
int DumpChunks::Dump(LoadedApk* apk) {
auto file = apk->GetFileCollection()->FindFile("resources.arsc");
if (!file) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to find resources.arsc in APK");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to find resources.arsc in APK");
return 1;
}
auto data = file->OpenAsData();
if (!data) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to open resources.arsc ");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to open resources.arsc ");
return 1;
}
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index ec320ecd2a32..76d33d7aa3b2 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -33,29 +33,30 @@ namespace aapt {
**/
class DumpApkCommand : public Command {
public:
- explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
+ explicit DumpApkCommand(const std::string&& name, text::Printer* printer,
+ android::IDiagnostics* diag)
: Command(name), printer_(printer), diag_(diag) {
- SetDescription("Dump information about an APK or APC.");
+ SetDescription("Dump information about an APK or APC.");
}
text::Printer* GetPrinter() {
return printer_;
}
- IDiagnostics* GetDiagnostics() {
+ android::IDiagnostics* GetDiagnostics() {
return diag_;
}
std::optional<std::string> GetPackageName(LoadedApk* apk) {
xml::Element* manifest_el = apk->GetManifest()->root.get();
if (!manifest_el) {
- GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
+ GetDiagnostics()->Error(android::DiagMessage() << "No AndroidManifest.");
return {};
}
xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
if (!attr) {
- GetDiagnostics()->Error(DiagMessage() << "No package name.");
+ GetDiagnostics()->Error(android::DiagMessage() << "No package name.");
return {};
}
return attr->value;
@@ -66,7 +67,7 @@ class DumpApkCommand : public Command {
int Action(const std::vector<std::string>& args) final {
if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
+ diag_->Error(android::DiagMessage() << "No dump apk specified.");
return 1;
}
@@ -86,13 +87,13 @@ class DumpApkCommand : public Command {
private:
text::Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
/** Command that prints contents of files generated from the compilation stage. */
class DumpAPCCommand : public Command {
public:
- explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpAPCCommand(text::Printer* printer, android::IDiagnostics* diag)
: Command("apc"), printer_(printer), diag_(diag) {
SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
@@ -104,7 +105,7 @@ class DumpAPCCommand : public Command {
private:
text::Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
bool no_values_ = false;
bool verbose_ = false;
};
@@ -124,13 +125,21 @@ class DumpBadgerCommand : public Command {
class DumpBadgingCommand : public DumpApkCommand {
public:
- explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpBadgingCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("badging", printer, diag) {
SetDescription("Print information extracted from the manifest of the APK.");
AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
&options_.include_meta_data);
}
+ void SetIncludeMetaData(bool value) {
+ options_.include_meta_data = value;
+ }
+
+ void SetOnlyPermissions(bool value) {
+ options_.only_permissions = value;
+ }
+
int Dump(LoadedApk* apk) override {
return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
}
@@ -141,7 +150,7 @@ class DumpBadgingCommand : public DumpApkCommand {
class DumpConfigsCommand : public DumpApkCommand {
public:
- explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpConfigsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("configurations", printer, diag) {
SetDescription("Print every configuration used by a resource in the APK.");
}
@@ -151,7 +160,7 @@ class DumpConfigsCommand : public DumpApkCommand {
class DumpPackageNameCommand : public DumpApkCommand {
public:
- explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpPackageNameCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("packagename", printer, diag) {
SetDescription("Print the package name of the APK.");
}
@@ -161,7 +170,7 @@ class DumpPackageNameCommand : public DumpApkCommand {
class DumpPermissionsCommand : public DumpApkCommand {
public:
- explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpPermissionsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("permissions", printer, diag) {
SetDescription("Print the permissions extracted from the manifest of the APK.");
}
@@ -175,7 +184,7 @@ class DumpPermissionsCommand : public DumpApkCommand {
class DumpStringsCommand : public DumpApkCommand {
public:
- explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpStringsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("strings", printer, diag) {
SetDescription("Print the contents of the resource table string pool in the APK.");
}
@@ -186,7 +195,7 @@ class DumpStringsCommand : public DumpApkCommand {
/** Prints the graph of parents of a style in an APK. */
class DumpStyleParentCommand : public DumpApkCommand {
public:
- explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpStyleParentCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("styleparents", printer, diag) {
SetDescription("Print the parents of a style in an APK.");
AddRequiredFlag("--style", "The name of the style to print", &style_);
@@ -200,7 +209,7 @@ class DumpStyleParentCommand : public DumpApkCommand {
class DumpTableCommand : public DumpApkCommand {
public:
- explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpTableCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("resources", printer, diag) {
SetDescription("Print the contents of the resource table from the APK.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
@@ -217,7 +226,7 @@ class DumpTableCommand : public DumpApkCommand {
class DumpXmlStringsCommand : public DumpApkCommand {
public:
- explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpXmlStringsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("xmlstrings", printer, diag) {
SetDescription("Print the string pool of a compiled xml in an APK.");
AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
@@ -231,7 +240,8 @@ class DumpXmlStringsCommand : public DumpApkCommand {
class DumpChunks : public DumpApkCommand {
public:
- DumpChunks(text::Printer* printer, IDiagnostics* diag) : DumpApkCommand("chunks", printer, diag) {
+ DumpChunks(text::Printer* printer, android::IDiagnostics* diag)
+ : DumpApkCommand("chunks", printer, diag) {
SetDescription("Print the chunk information of the compiled resources.arsc in the APK.");
}
@@ -241,7 +251,7 @@ class DumpChunks : public DumpApkCommand {
/** Prints the tree of a compiled xml in an APK. */
class DumpXmlTreeCommand : public DumpApkCommand {
public:
- explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpXmlTreeCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("xmltree", printer, diag) {
SetDescription("Print the tree of a compiled xml in an APK.");
AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
@@ -255,7 +265,7 @@ class DumpXmlTreeCommand : public DumpApkCommand {
class DumpOverlayableCommand : public DumpApkCommand {
public:
- explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpOverlayableCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("overlayable", printer, diag) {
SetDescription("Print the <overlayable> resources of an APK.");
}
@@ -266,7 +276,7 @@ class DumpOverlayableCommand : public DumpApkCommand {
/** The default dump command. Performs no action because a subcommand is required. */
class DumpCommand : public Command {
public:
- explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpCommand(text::Printer* printer, android::IDiagnostics* diag)
: Command("dump", "d"), diag_(diag) {
AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
@@ -285,16 +295,16 @@ class DumpCommand : public Command {
int Action(const std::vector<std::string>& args) override {
if (args.size() == 0) {
- diag_->Error(DiagMessage() << "no subcommand specified");
+ diag_->Error(android::DiagMessage() << "no subcommand specified");
} else {
- diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ diag_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'");
}
Usage(&std::cerr);
return 1;
}
private:
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
} // namespace aapt
diff --git a/tools/aapt2/cmd/Dump_test.cpp b/tools/aapt2/cmd/Dump_test.cpp
new file mode 100644
index 000000000000..03da364f4f3e
--- /dev/null
+++ b/tools/aapt2/cmd/Dump_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "Dump.h"
+
+#include "LoadedApk.h"
+#include "io/StringStream.h"
+#include "test/Test.h"
+#include "text/Printer.h"
+
+using ::aapt::io::StringOutputStream;
+using ::aapt::text::Printer;
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using DumpTest = CommandTestFixture;
+
+static android::NoOpDiagnostics noop_diag;
+
+void DumpBadgingToString(LoadedApk* loaded_apk, std::string* output, bool include_meta_data = false,
+ bool only_permissions = false) {
+ StringOutputStream output_stream(output);
+ Printer printer(&output_stream);
+
+ DumpBadgingCommand command(&printer, &noop_diag);
+ command.SetIncludeMetaData(include_meta_data);
+ command.SetOnlyPermissions(only_permissions);
+ ASSERT_EQ(command.Dump(loaded_apk), 0);
+ output_stream.Flush();
+}
+
+TEST_F(DumpTest, DumpBadging) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "minimal.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output);
+
+ std::string expected;
+ auto expected_path = file::BuildPath({android::base::GetExecutableDirectory(),
+ "integration-tests", "DumpTest", "minimal_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingAllComponents) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ true);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingPermissionsOnly) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ false,
+ /* only_permissions= */ true);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_permissions_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 790f2b34c58b..82f2e8f7ed73 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -17,20 +17,13 @@
#include "Link.h"
#include <sys/stat.h>
-#include <cinttypes>
#include <algorithm>
+#include <cinttypes>
#include <queue>
#include <unordered_map>
#include <vector>
-#include "android-base/errors.h"
-#include "android-base/expected.h"
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/Locale.h"
-#include "androidfw/StringPiece.h"
-
#include "AppInfo.h"
#include "Debug.h"
#include "LoadedApk.h"
@@ -38,6 +31,13 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/errors.h"
+#include "android-base/expected.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Locale.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "compile/XmlIdCollector.h"
@@ -98,7 +98,7 @@ constexpr uint8_t kAndroidPackageId = 0x01;
class LinkContext : public IAaptContext {
public:
- explicit LinkContext(IDiagnostics* diagnostics)
+ explicit LinkContext(android::IDiagnostics* diagnostics)
: diagnostics_(diagnostics), name_mangler_({}), symbols_(&name_mangler_) {
}
@@ -110,7 +110,7 @@ class LinkContext : public IAaptContext {
package_type_ = type;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return diagnostics_;
}
@@ -170,7 +170,7 @@ class LinkContext : public IAaptContext {
DISALLOW_COPY_AND_ASSIGN(LinkContext);
PackageType package_type_ = PackageType::kApp;
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
NameMangler name_mangler_;
std::string compilation_package_;
uint8_t package_id_ = 0x0;
@@ -216,14 +216,16 @@ class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
// Check that this doesn't overlap another resource.
if (DefaultSymbolTableDelegate::FindById(rewritten_id, sources) != nullptr) {
// The ID overlaps, so log a message (since this is a weird failure) and fail.
- context_->GetDiagnostics()->Error(DiagMessage() << "Failed to rewrite " << name
- << " for pre-O feature split support");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "Failed to rewrite " << name
+ << " for pre-O feature split support");
return {};
}
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "rewriting " << name << " (" << *id
- << ") -> (" << rewritten_id << ")");
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "rewriting " << name << " (" << *id << ") -> ("
+ << rewritten_id << ")");
}
*id = rewritten_id;
@@ -243,14 +245,14 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
OutputFormat format, IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values="
- << (keep_raw_values ? "true" : "false")
- << ")");
+ context->GetDiagnostics()->Note(android::DiagMessage(path)
+ << "writing to archive (keep_raw_values="
+ << (keep_raw_values ? "true" : "false") << ")");
}
switch (format) {
case OutputFormat::kApk: {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
XmlFlattenerOptions options = {};
options.keep_raw_values = keep_raw_values;
options.use_utf16 = utf16;
@@ -278,14 +280,15 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
}
// Inflates an XML file from the source path.
-static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, IDiagnostics* diag) {
+static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path,
+ android::IDiagnostics* diag) {
TRACE_CALL();
FileInputStream fin(path);
if (fin.HadError()) {
- diag->Error(DiagMessage(path) << "failed to load XML file: " << fin.GetError());
+ diag->Error(android::DiagMessage(path) << "failed to load XML file: " << fin.GetError());
return {};
}
- return xml::Inflate(&fin, diag, Source(path));
+ return xml::Inflate(&fin, diag, android::Source(path));
}
struct ResourceFileFlattenerOptions {
@@ -451,10 +454,10 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
ResourceTable* table, FileOperation* file_op) {
TRACE_CALL();
xml::XmlResource* doc = file_op->xml_to_flatten.get();
- const Source& src = doc->file.source;
+ const android::Source& src = doc->file.source;
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "linking " << src.path << " (" << doc->file.name << ")");
}
@@ -545,7 +548,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
io::IFile* file = file_ref->file;
if (!file) {
- context_->GetDiagnostics()->Error(DiagMessage(file_ref->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file_ref->GetSource())
<< "file not found");
return false;
}
@@ -556,12 +559,12 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.config = config_value->config;
file_op.file_to_copy = file;
- if (type->type != ResourceType::kRaw &&
+ if (type->named_type.type != ResourceType::kRaw &&
(file_ref->type == ResourceFile::Type::kBinaryXml ||
file_ref->type == ResourceFile::Type::kProtoXml)) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to open file");
return false;
}
@@ -569,7 +572,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (file_ref->type == ResourceFile::Type::kProtoXml) {
pb::XmlNode pb_xml_node;
if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to parse proto XML");
return false;
}
@@ -577,7 +580,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
std::string error;
file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
if (file_op.xml_to_flatten == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to deserialize proto XML: " << error);
return false;
}
@@ -585,7 +588,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
std::string error_str;
file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(), &error_str);
if (file_op.xml_to_flatten == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to parse binary XML: " << error_str);
return false;
}
@@ -596,7 +599,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.xml_to_flatten->file.config = config_value->config;
file_op.xml_to_flatten->file.source = file_ref->GetSource();
- file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name);
+ file_op.xml_to_flatten->file.name =
+ ResourceName(pkg->name, type->named_type, entry->name);
}
// NOTE(adamlesinski): Explicitly construct a StringPiece here, or
@@ -620,10 +624,10 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (drawable_entry != kDrawableVersions.end()) {
if (drawable_entry->second > context_->GetMinSdkVersion()
&& drawable_entry->second > config.sdkVersion) {
- context_->GetDiagnostics()->Error(DiagMessage(file_op.xml_to_flatten->file.source)
- << "<" << drawable_entry->first << "> elements "
- << "require a sdk version of at least "
- << (int16_t) drawable_entry->second);
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(file_op.xml_to_flatten->file.source)
+ << "<" << drawable_entry->first << "> elements "
+ << "require a sdk version of at least " << (int16_t)drawable_entry->second);
error = true;
continue;
}
@@ -641,7 +645,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (doc->file.config != file_op.config) {
// Only add the new versioned configurations.
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(doc->file.source)
+ context_->GetDiagnostics()->Note(android::DiagMessage(doc->file.source)
<< "auto-versioning resource from config '"
<< config << "' -> '" << doc->file.config << "'");
}
@@ -679,12 +683,12 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
return !error;
}
-static bool WriteStableIdMapToPath(IDiagnostics* diag,
+static bool WriteStableIdMapToPath(android::IDiagnostics* diag,
const std::unordered_map<ResourceName, ResourceId>& id_map,
const std::string& id_map_path) {
io::FileOutputStream fout(id_map_path);
if (fout.HadError()) {
- diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
+ diag->Error(android::DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
return false;
}
@@ -699,17 +703,17 @@ static bool WriteStableIdMapToPath(IDiagnostics* diag,
fout.Flush();
if (fout.HadError()) {
- diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
+ diag->Error(android::DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
return false;
}
return true;
}
-static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
+static bool LoadStableIdMap(android::IDiagnostics* diag, const std::string& path,
std::unordered_map<ResourceName, ResourceId>* out_id_map) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
- diag->Error(DiagMessage(path) << "failed reading stable ID file");
+ diag->Error(android::DiagMessage(path) << "failed reading stable ID file");
return false;
}
@@ -724,7 +728,7 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
auto iter = std::find(line.begin(), line.end(), '=');
if (iter == line.end()) {
- diag->Error(DiagMessage(Source(path, line_no)) << "missing '='");
+ diag->Error(android::DiagMessage(android::Source(path, line_no)) << "missing '='");
return false;
}
@@ -732,8 +736,8 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
StringPiece res_name_str =
util::TrimWhitespace(line.substr(0, std::distance(line.begin(), iter)));
if (!ResourceUtils::ParseResourceName(res_name_str, &name)) {
- diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource name '" << res_name_str
- << "'");
+ diag->Error(android::DiagMessage(android::Source(path, line_no))
+ << "invalid resource name '" << res_name_str << "'");
return false;
}
@@ -743,8 +747,8 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str);
if (!maybe_id) {
- diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource ID '" << res_id_str
- << "'");
+ diag->Error(android::DiagMessage(android::Source(path, line_no))
+ << "invalid resource ID '" << res_id_str << "'");
return false;
}
@@ -834,20 +838,21 @@ class Linker {
auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "including " << path);
}
std::string error;
auto zip_collection = io::ZipFileCollection::Create(path, &error);
if (zip_collection == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open APK: " << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to open APK: " << error);
return false;
}
if (zip_collection->FindFile(kProtoResourceTablePath) != nullptr) {
// Load this as a static library include.
std::unique_ptr<LoadedApk> static_apk = LoadedApk::LoadProtoApkFromFileCollection(
- Source(path), std::move(zip_collection), context_->GetDiagnostics());
+ android::Source(path), std::move(zip_collection), context_->GetDiagnostics());
if (static_apk == nullptr) {
return false;
}
@@ -856,7 +861,8 @@ class Linker {
// Can't include static libraries when not building a static library (they have no IDs
// assigned).
context_->GetDiagnostics()->Error(
- DiagMessage(path) << "can't include static library when not building a static lib");
+ android::DiagMessage(path)
+ << "can't include static library when not building a static lib");
return false;
}
@@ -868,7 +874,8 @@ class Linker {
if (options_.no_static_lib_packages && !table->packages.empty()) {
auto lib_package_result = GetStaticLibraryPackage(table);
if (!lib_package_result.has_value()) {
- context_->GetDiagnostics()->Error(DiagMessage(path) << lib_package_result.error());
+ context_->GetDiagnostics()->Error(android::DiagMessage(path)
+ << lib_package_result.error());
return false;
}
lib_package_result.value()->name = context_->GetCompilationPackage();
@@ -879,7 +886,7 @@ class Linker {
static_library_includes_.push_back(std::move(static_apk));
} else {
if (!asset_source->AddAssetPath(path)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to load include path " << path);
return false;
}
@@ -912,7 +919,8 @@ class Linker {
return true;
}
- std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
+ std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res,
+ android::IDiagnostics* diag) {
TRACE_CALL();
// Make sure the first element is <manifest> with package attribute.
xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get());
@@ -923,13 +931,13 @@ class Linker {
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
return {};
}
xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res->file.source)
+ diag->Error(android::DiagMessage(xml_res->file.source)
<< "<manifest> must have a 'package' attribute");
return {};
}
@@ -939,7 +947,7 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode '" << version_code_attr->value << "'");
return {};
}
@@ -950,9 +958,9 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
- << "invalid android:versionCodeMajor '"
- << version_code_major_attr->value << "'");
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ << "invalid android:versionCodeMajor '" << version_code_major_attr->value
+ << "'");
return {};
}
app_info.version_code_major = maybe_code.value();
@@ -962,7 +970,7 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode '" << revision_code_attr->value << "'");
return {};
}
@@ -1009,21 +1017,21 @@ class Linker {
// We have a package that is not related to the one we're building!
for (const auto& type : package->types) {
for (const auto& entry : type->entries) {
- ResourceNameRef res_name(package->name, type->type, entry->name);
+ ResourceNameRef res_name(package->name, type->named_type, entry->name);
for (const auto& config_value : entry->values) {
// Special case the occurrence of an ID that is being generated
// for the 'android' package. This is due to legacy reasons.
if (ValueCast<Id>(config_value->value.get()) && package->name == "android") {
- context_->GetDiagnostics()->Warn(DiagMessage(config_value->value->GetSource())
- << "generated id '" << res_name
- << "' for external package '" << package->name
- << "'");
+ context_->GetDiagnostics()->Warn(
+ android::DiagMessage(config_value->value->GetSource())
+ << "generated id '" << res_name << "' for external package '" << package->name
+ << "'");
} else {
- context_->GetDiagnostics()->Error(DiagMessage(config_value->value->GetSource())
- << "defined resource '" << res_name
- << "' for external package '" << package->name
- << "'");
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(config_value->value->GetSource())
+ << "defined resource '" << res_name << "' for external package '"
+ << package->name << "'");
error = true;
}
}
@@ -1046,9 +1054,10 @@ class Linker {
for (const auto& type : package->types) {
for (const auto& entry : type->entries) {
if (entry->id) {
- ResourceNameRef res_name(package->name, type->type, entry->name);
- context_->GetDiagnostics()->Error(DiagMessage() << "resource " << res_name << " has ID "
- << entry->id.value() << " assigned");
+ ResourceNameRef res_name(package->name, type->named_type, entry->name);
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "resource " << res_name << " has ID "
+ << entry->id.value() << " assigned");
return false;
}
}
@@ -1057,6 +1066,84 @@ class Linker {
return true;
}
+ bool VerifyLocaleFormat(xml::XmlResource* manifest, android::IDiagnostics* diag) {
+ // Skip it if the Manifest doesn't declare the localeConfig attribute within the <application>
+ // element.
+ const xml::Element* application = manifest->root->FindChild("", "application");
+ if (!application) {
+ return true;
+ }
+ const xml::Attribute* localeConfig =
+ application->FindAttribute(xml::kSchemaAndroid, "localeConfig");
+ if (!localeConfig) {
+ return true;
+ }
+
+ if (localeConfig->compiled_value) {
+ const auto localeconfig_reference = ValueCast<Reference>(localeConfig->compiled_value.get());
+ const auto localeconfig_entry =
+ ResolveTableEntry(context_, &final_table_, localeconfig_reference);
+ if (!localeconfig_entry) {
+ return true;
+ }
+
+ for (const auto& value : localeconfig_entry->values) {
+ // Load an XML file which is linked from the localeConfig attribute.
+ const std::string& path = value->value->GetSource().path;
+ std::unique_ptr<xml::XmlResource> localeConfig_xml = LoadXml(path, diag);
+ if (!localeConfig_xml) {
+ diag->Error(android::DiagMessage(path) << "can't load the XML");
+ return false;
+ }
+
+ xml::Element* localeConfig_el = xml::FindRootElement(localeConfig_xml->root.get());
+ if (!localeConfig_el) {
+ diag->Error(android::DiagMessage(path) << "no root tag defined");
+ return false;
+ }
+ if (localeConfig_el->name != "locale-config") {
+ diag->Error(android::DiagMessage(path)
+ << "invalid element name: " << localeConfig_el->name
+ << ", expected: locale-config");
+ return false;
+ }
+
+ for (const xml::Element* child_el : localeConfig_el->GetChildElements()) {
+ if (child_el->name == "locale") {
+ if (const xml::Attribute* locale_name_attr =
+ child_el->FindAttribute(xml::kSchemaAndroid, "name")) {
+ const std::string& locale_name = locale_name_attr->value;
+ const std::string valid_name = ConvertToBCP47Tag(locale_name);
+
+ // Start to verify the locale format
+ ConfigDescription config;
+ if (!ConfigDescription::Parse(valid_name, &config)) {
+ diag->Error(android::DiagMessage(path) << "invalid configuration: " << locale_name);
+ return false;
+ }
+ } else {
+ diag->Error(android::DiagMessage(path) << "the attribute android:name is not found");
+ return false;
+ }
+ } else {
+ diag->Error(android::DiagMessage(path)
+ << "invalid element name: " << child_el->name << ", expected: locale");
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ std::string ConvertToBCP47Tag(const std::string& locale) {
+ std::string bcp47tag = "b+";
+ bcp47tag += locale;
+ std::replace(bcp47tag.begin(), bcp47tag.end(), '-', '+');
+
+ return bcp47tag;
+ }
+
std::unique_ptr<IArchiveWriter> MakeArchiveWriter(const StringPiece& out) {
if (options_.output_to_directory) {
return CreateDirectoryArchiveWriter(context_->GetDiagnostics(), out);
@@ -1069,10 +1156,11 @@ class Linker {
TRACE_CALL();
switch (format) {
case OutputFormat::kApk: {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
TableFlattener flattener(options_.table_flattener_options, &buffer);
if (!flattener.Consume(context_, table)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to flatten resource table");
return false;
}
@@ -1105,7 +1193,7 @@ class Linker {
out_path = options_.generate_java_class_path.value();
file::AppendPath(&out_path, file::PackageToPath(out_package));
if (!file::mkdirs(out_path)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to create directory '" << out_path << "'");
return false;
}
@@ -1114,8 +1202,9 @@ class Linker {
fout = util::make_unique<io::FileOutputStream>(out_path);
if (fout->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout->GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed writing to '" << out_path
+ << "': " << fout->GetError());
return false;
}
}
@@ -1124,7 +1213,7 @@ class Linker {
if (out_text_symbols_path) {
fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
if (fout_text->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to '" << out_text_symbols_path.value()
<< "': " << fout_text->GetError());
return false;
@@ -1133,7 +1222,7 @@ class Linker {
JavaClassGenerator generator(context_, table, java_options);
if (!generator.Generate(package_name_to_generate, out_package, fout.get(), fout_text.get())) {
- context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage(out_path) << generator.GetError());
return false;
}
@@ -1257,8 +1346,8 @@ class Linker {
file::AppendPath(&out_path, file::PackageToPath(package_utf8));
if (!file::mkdirs(out_path)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create directory '" << out_path
- << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create directory '" << out_path << "'");
return false;
}
@@ -1266,8 +1355,8 @@ class Linker {
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
+ << "': " << fout.GetError());
return false;
}
@@ -1276,8 +1365,8 @@ class Linker {
fout.Flush();
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_path
+ << "': " << fout.GetError());
return false;
}
return true;
@@ -1292,8 +1381,8 @@ class Linker {
const std::string& out_path = out.value();
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
+ << "': " << fout.GetError());
return false;
}
@@ -1302,8 +1391,8 @@ class Linker {
fout.Flush();
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_path
+ << "': " << fout.GetError());
return false;
}
return true;
@@ -1312,12 +1401,13 @@ class Linker {
bool MergeStaticLibrary(const std::string& input, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input);
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "merging static library " << input);
}
std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(input, context_->GetDiagnostics());
if (apk == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << "invalid static library");
return false;
}
@@ -1328,7 +1418,7 @@ class Linker {
auto lib_package_result = GetStaticLibraryPackage(table);
if (!lib_package_result.has_value()) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << lib_package_result.error());
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << lib_package_result.error());
return false;
}
@@ -1347,12 +1437,12 @@ class Linker {
// Clear the package name, so as to make the resources look like they are coming from the
// local package.
pkg->name = "";
- result = table_merger_->Merge(Source(input), table, override);
+ result = table_merger_->Merge(android::Source(input), table, override);
} else {
// This is the proper way to merge libraries, where the package name is
// preserved and resource names are mangled.
- result = table_merger_->MergeAndMangle(Source(input), pkg->name, table);
+ result = table_merger_->MergeAndMangle(android::Source(input), pkg->name, table);
}
if (!result) {
@@ -1364,7 +1454,7 @@ class Linker {
return true;
}
- bool MergeExportedSymbols(const Source& source,
+ bool MergeExportedSymbols(const android::Source& source,
const std::vector<SourcedResourceName>& exported_symbols) {
TRACE_CALL();
// Add the exports of this file to the table.
@@ -1394,7 +1484,7 @@ class Linker {
bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "merging '" << compiled_file.name
<< "' from compiled file " << compiled_file.source);
}
@@ -1413,14 +1503,14 @@ class Linker {
bool MergeArchive(const std::string& input, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging archive " << input);
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "merging archive " << input);
}
std::string error_str;
std::unique_ptr<io::ZipFileCollection> collection =
io::ZipFileCollection::Create(input, &error_str);
if (!collection) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << error_str);
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << error_str);
return false;
}
@@ -1460,31 +1550,32 @@ class Linker {
// where we could have other files like classes.dex.
bool MergeFile(io::IFile* file, bool override) {
TRACE_CALL();
- const Source& src = file->GetSource();
+ const android::Source& src = file->GetSource();
if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) {
// Since AAPT compiles these file types and appends .flat to them, seeing
// their raw extensions is a sign that they weren't compiled.
const StringPiece file_type = util::EndsWith(src.path, ".xml") ? "XML" : "PNG";
- context_->GetDiagnostics()->Error(DiagMessage(src) << "uncompiled " << file_type
- << " file passed as argument. Must be "
- "compiled first into .flat file.");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "uncompiled " << file_type
+ << " file passed as argument. Must be "
+ "compiled first into .flat file.");
return false;
} else if (!util::EndsWith(src.path, ".apc") && !util::EndsWith(src.path, ".flat")) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring unrecognized file");
+ context_->GetDiagnostics()->Warn(android::DiagMessage(src) << "ignoring unrecognized file");
return true;
}
}
std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream();
if (input_stream == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to open file");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src) << "failed to open file");
return false;
}
if (input_stream->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to open file: " << input_stream->GetError());
return false;
}
@@ -1493,7 +1584,7 @@ class Linker {
ContainerReader reader(input_stream.get());
if (reader.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to read file: " << reader.GetError());
return false;
}
@@ -1503,21 +1594,22 @@ class Linker {
TRACE_NAME(std::string("Process ResTable:") + file->GetSource().path);
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read resource table: "
- << entry->GetError());
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(src) << "failed to read resource table: " << entry->GetError());
return false;
}
ResourceTable table;
std::string error;
if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to deserialize resource table: " << error);
return false;
}
if (!table_merger_->Merge(src, &table, override)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to merge resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "failed to merge resource table");
return false;
}
} else if (entry->Type() == ContainerEntryType::kResFile) {
@@ -1526,15 +1618,15 @@ class Linker {
off64_t offset;
size_t len;
if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &len)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to get resource file: "
- << entry->GetError());
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(src) << "failed to get resource file: " << entry->GetError());
return false;
}
ResourceFile resource_file;
std::string error;
if (!DeserializeCompiledFileFromPb(pb_compiled_file, &resource_file, &error)) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to read compiled header: " << error);
return false;
}
@@ -1563,10 +1655,10 @@ class Linker {
auto iter = merged_assets.find(full_key);
if (iter == merged_assets.end()) {
- merged_assets.emplace(std::move(full_key),
- util::make_unique<io::RegularFile>(Source(std::move(full_path))));
+ merged_assets.emplace(std::move(full_key), util::make_unique<io::RegularFile>(
+ android::Source(std::move(full_path))));
} else if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Warn(DiagMessage(iter->second->GetSource())
+ context_->GetDiagnostics()->Warn(android::DiagMessage(iter->second->GetSource())
<< "asset file overrides '" << full_path << "'");
}
}
@@ -1651,10 +1743,10 @@ class Linker {
continue;
}
- context_->GetDiagnostics()->Note(DiagMessage() << "generating "
- << round_icon_reference->name.value()
- << " with config \"" << config_value->config
- << "\" for round icon compatibility");
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "generating " << round_icon_reference->name.value()
+ << " with config \"" << config_value->config
+ << "\" for round icon compatibility");
CloningValueTransformer cloner(&table->string_pool);
auto value = icon_reference->Transform(cloner);
@@ -1680,7 +1772,7 @@ class Linker {
if (util::IsAndroidSharedUserId(context_->GetCompilationPackage(), shared_user_id)) {
return true;
}
- DiagMessage error_msg(manifest_el->line_number);
+ android::DiagMessage error_msg(manifest_el->line_number);
error_msg << "attribute 'sharedUserId' in <manifest> tag is not a valid shared user id: '"
<< shared_user_id << "'";
if (options_.manifest_fixer_options.warn_validation) {
@@ -1756,7 +1848,7 @@ class Linker {
ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
if (!file_flattener.Flatten(table, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed linking file resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed linking file resources");
return false;
}
@@ -1787,8 +1879,8 @@ class Linker {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(
- DiagMessage() << "rewriting resource package name for feature split to '"
- << new_package_name << "'");
+ android::DiagMessage() << "rewriting resource package name for feature split to '"
+ << new_package_name << "'");
}
package_to_rewrite->name = new_package_name;
}
@@ -1808,7 +1900,7 @@ class Linker {
}
if (!success) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to write resource table");
}
return success;
}
@@ -1869,7 +1961,7 @@ class Linker {
// Verify we're building a regular app.
if (context_->GetPackageType() != PackageType::kApp) {
context_->GetDiagnostics()->Error(
- DiagMessage() << "package 'android' can only be built as a regular app");
+ android::DiagMessage() << "package 'android' can only be built as a regular app");
return 1;
}
}
@@ -1882,7 +1974,7 @@ class Linker {
table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< StringPrintf("linking package '%s' using package ID %02x",
context_->GetCompilationPackage().data(),
context_->GetPackageId()));
@@ -1903,14 +1995,14 @@ class Linker {
for (const std::string& input : input_files) {
if (!MergePath(input, false)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing input");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed parsing input");
return 1;
}
}
for (const std::string& input : options_.overlay_files) {
if (!MergePath(input, true)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing overlays");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed parsing overlays");
return 1;
}
}
@@ -1923,14 +2015,15 @@ class Linker {
PrivateAttributeMover mover;
if (context_->GetPackageId() == kAndroidPackageId &&
!mover.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed moving private attributes");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed moving private attributes");
return 1;
}
// Assign IDs if we are building a regular app.
IdAssigner id_assigner(&options_.stable_id_map);
if (!id_assigner.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed assigning IDs");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed assigning IDs");
return 1;
}
@@ -1939,7 +2032,7 @@ class Linker {
for (auto& package : final_table_.packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- ResourceName name(package->name, type->type, entry->name);
+ ResourceName name(package->name, type->named_type, entry->name);
// The IDs are guaranteed to exist.
options_.stable_id_map[std::move(name)] = entry->id.value();
}
@@ -1974,7 +2067,7 @@ class Linker {
// are just identifiers.
if (context_->GetMinSdkVersion() < SDK_O && context_->GetPackageType() == PackageType::kApp) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "enabling pre-O feature split ID rewriting");
}
context_->GetExternalSymbols()->SetDelegate(
@@ -1985,7 +2078,7 @@ class Linker {
// We want to force any references to these to fail the build.
if (!options_.no_resource_removal) {
if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed removing resources with no defaults");
return 1;
}
@@ -1993,19 +2086,19 @@ class Linker {
ReferenceLinker linker;
if (!options_.merge_only && !linker.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed linking references");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed linking references");
return 1;
}
if (context_->GetPackageType() == PackageType::kStaticLib) {
if (!options_.products.empty()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "can't select products when building static library");
}
} else {
ProductFilter product_filter(options_.products);
if (!product_filter.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed stripping products");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed stripping products");
return 1;
}
}
@@ -2013,14 +2106,14 @@ class Linker {
if (!options_.no_auto_version) {
AutoVersioner versioner;
if (!versioner.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed versioning styles");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed versioning styles");
return 1;
}
}
if (context_->GetPackageType() != PackageType::kStaticLib && context_->GetMinSdkVersion() > 0) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "collapsing resource versions for minimum SDK "
<< context_->GetMinSdkVersion());
}
@@ -2039,9 +2132,8 @@ class Linker {
ConfigDescription config_description;
if (!ConfigDescription::Parse(config_string, &config_description)) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "failed to parse --excluded-configs "
- << config_string);
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage() << "failed to parse --excluded-configs " << config_string);
return 1;
}
@@ -2050,7 +2142,8 @@ class Linker {
ResourceExcluder excluder(excluded_configs);
if (!excluder.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed excluding configurations");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed excluding configurations");
return 1;
}
}
@@ -2058,7 +2151,7 @@ class Linker {
if (!options_.no_resource_deduping) {
ResourceDeduper deduper;
if (!deduper.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed deduping resources");
return 1;
}
}
@@ -2070,7 +2163,7 @@ class Linker {
if (context_->GetPackageType() == PackageType::kStaticLib) {
if (options_.table_splitter_options.config_filter != nullptr ||
!options_.table_splitter_options.preferred_densities.empty()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "can't strip resources when building static library");
}
} else {
@@ -2081,7 +2174,7 @@ class Linker {
AdjustSplitConstraintsForMinSdk(context_->GetMinSdkVersion(), options_.split_constraints);
if (origConstraintSize != options_.split_constraints.size()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "requested to split resources prior to min sdk of "
<< context_->GetMinSdkVersion());
}
@@ -2096,7 +2189,7 @@ class Linker {
auto split_constraints_iter = options_.split_constraints.begin();
for (std::unique_ptr<ResourceTable>& split_table : table_splitter.splits()) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(*path_iter)
+ context_->GetDiagnostics()->Note(android::DiagMessage(*path_iter)
<< "generating split with configurations '"
<< util::Joiner(split_constraints_iter->configs, ", ")
<< "'");
@@ -2104,7 +2197,7 @@ class Linker {
std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(*path_iter);
if (!archive_writer) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to create archive");
return 1;
}
@@ -2114,7 +2207,7 @@ class Linker {
XmlReferenceLinker linker(&final_table_);
if (!linker.Consume(context_, split_manifest.get())) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to create Split AndroidManifest.xml");
return 1;
}
@@ -2132,7 +2225,7 @@ class Linker {
// Start writing the base APK.
std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(options_.output_path);
if (!archive_writer) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to create archive");
return 1;
}
@@ -2176,10 +2269,14 @@ class Linker {
}
if (error) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed processing manifest");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed processing manifest");
return 1;
}
+ if (!VerifyLocaleFormat(manifest_xml.get(), context_->GetDiagnostics())) {
+ return 1;
+ };
+
if (!WriteApk(archive_writer.get(), &proguard_keep_set, manifest_xml.get(), &final_table_)) {
return 1;
}
@@ -2245,7 +2342,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::AppendArgsFromFile(path, &arg_list, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
@@ -2259,7 +2356,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::AppendArgsFromFile(path, &options_.overlay_files, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
@@ -2272,9 +2369,9 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
}
if (int{shared_lib_} + int{static_lib_} + int{proto_format_} > 1) {
- context.GetDiagnostics()->Error(
- DiagMessage()
- << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
+ context.GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
return 1;
}
@@ -2282,15 +2379,16 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
// If a shared library styleable in a public R.java uses a private attribute, attempting to
// reference the private attribute within the styleable array will cause a link error because
// the private attribute will not be emitted in the public R.java.
- context.GetDiagnostics()->Error(DiagMessage()
+ context.GetDiagnostics()->Error(android::DiagMessage()
<< "--shared-lib cannot currently be used in combination with"
<< " --private-symbols");
return 1;
}
if (options_.merge_only && !static_lib_) {
- context.GetDiagnostics()->Error(
- DiagMessage() << "the --merge-only flag can be only used when building a static library");
+ context.GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "the --merge-only flag can be only used when building a static library");
return 1;
}
@@ -2311,15 +2409,16 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
if (package_id_) {
if (context.GetPackageType() != PackageType::kApp) {
context.GetDiagnostics()->Error(
- DiagMessage() << "can't specify --package-id when not building a regular app");
+ android::DiagMessage() << "can't specify --package-id when not building a regular app");
return 1;
}
const std::optional<uint32_t> maybe_package_id_int =
ResourceUtils::ParseInt(package_id_.value());
if (!maybe_package_id_int) {
- context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value()
- << "' is not a valid integer");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "package ID '" << package_id_.value()
+ << "' is not a valid integer");
return 1;
}
@@ -2328,7 +2427,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
|| package_id_int == kFrameworkPackageId
|| (!options_.allow_reserved_package_id && package_id_int < kAppPackageId)) {
context.GetDiagnostics()->Error(
- DiagMessage() << StringPrintf(
+ android::DiagMessage() << StringPrintf(
"invalid package ID 0x%02x. Must be in the range 0x7f-0xff.", package_id_int));
return 1;
}
@@ -2392,7 +2491,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = regex.substr(1, regex.size() -1);
std::string error;
if (!file::AppendSetArgsFromFile(path, &options_.extensions_to_not_compress, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index d8c76e297ec5..a5623cb1f1e1 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -20,12 +20,12 @@
#include <regex>
#include "Command.h"
-#include "Diagnostics.h"
#include "Resource.h"
-#include "split/TableSplitter.h"
+#include "androidfw/IDiagnostics.h"
#include "format/binary/TableFlattener.h"
#include "format/proto/ProtoSerialize.h"
#include "link/ManifestFixer.h"
+#include "split/TableSplitter.h"
#include "trace/TraceBuffer.h"
namespace aapt {
@@ -111,8 +111,7 @@ struct LinkOptions {
class LinkCommand : public Command {
public:
- explicit LinkCommand(IDiagnostics* diag) : Command("link", "l"),
- diag_(diag) {
+ explicit LinkCommand(android::IDiagnostics* diag) : Command("link", "l"), diag_(diag) {
SetDescription("Links resources into an apk.");
AddRequiredFlag("-o", "Output path.", &options_.output_path, Command::kPath);
AddRequiredFlag("--manifest", "Path to the Android manifest to build.",
@@ -316,7 +315,7 @@ class LinkCommand : public Command {
int Action(const std::vector<std::string>& args) override;
private:
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
LinkOptions options_;
std::vector<std::string> overlay_arg_list_;
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 430c184ef87d..683ccad2fdf2 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -19,9 +19,11 @@
#include <android-base/file.h>
#include "AppInfo.h"
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "test/Test.h"
+using android::ConfigDescription;
using testing::Eq;
using testing::HasSubstr;
using testing::IsNull;
@@ -86,7 +88,8 @@ TEST_F(LinkTest, KeepRawXmlStrings) {
// Check that the raw string index has been set to the correct string pool entry
int32_t raw_index = tree.getAttributeValueStringID(0);
ASSERT_THAT(raw_index, Ne(-1));
- EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+ EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
+ Eq("007"));
}
TEST_F(LinkTest, NoCompressAssets) {
@@ -409,7 +412,7 @@ struct SourceXML {
static void BuildApk(const std::vector<SourceXML>& source_files, const std::string& apk_path,
LinkCommandBuilder&& link_args, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
TemporaryDir res_dir;
TemporaryDir compiled_res_dir;
for (auto& source_file : source_files) {
@@ -422,7 +425,7 @@ static void BuildApk(const std::vector<SourceXML>& source_files, const std::stri
static void BuildSDK(const std::vector<SourceXML>& source_files, const std::string& apk_path,
const std::string& java_root_path, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
auto android_manifest = ManifestBuilder(fixture).SetPackageName("android").Build();
auto android_link_args = LinkCommandBuilder(fixture)
@@ -434,7 +437,7 @@ static void BuildSDK(const std::vector<SourceXML>& source_files, const std::stri
}
static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string& java_path,
- CommandTestFixture* fixture, IDiagnostics* diag) {
+ CommandTestFixture* fixture, android::IDiagnostics* diag) {
const std::string android_values =
R"(<resources>
<public type="attr" name="finalized_res" id="0x01010001"/>
@@ -470,7 +473,7 @@ static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string&
}
static void BuildFinalizedSDK(const std::string& apk_path, const std::string& java_path,
- CommandTestFixture* fixture, IDiagnostics* diag) {
+ CommandTestFixture* fixture, android::IDiagnostics* diag) {
const std::string android_values =
R"(<resources>
<public type="attr" name="finalized_res" id="0x01010001"/>
@@ -510,7 +513,7 @@ static void BuildFinalizedSDK(const std::string& apk_path, const std::string& ja
static void BuildAppAgainstSDK(const std::string& apk_path, const std::string& java_path,
const std::string& sdk_path, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
const std::string app_values =
R"(<resources xmlns:android="http://schemas.android.com/apk/res/android">
<attr name="bar" />
@@ -783,4 +786,51 @@ TEST_F(LinkTest, MacroSubstitution) {
EXPECT_THAT(xml_attrs[1].value, Eq("Hello World!"));
}
+TEST_F(LinkTest, ParseLocaleConfig) {
+ StdErrDiagnostics diag;
+ const std::string xml_values =
+ R"(<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="pt"/>
+ <locale android:name="chr"/>
+ <locale android:name="chr-US"/>
+ <locale android:name="zh-Hant"/>
+ <locale android:name="es-419"/>
+ <locale android:name="en-US"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)";
+
+ const std::string res = GetTestPath("test-res");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/locale_config.xml"), xml_values, res, &diag));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ auto link_args = LinkCommandBuilder(this)
+ .SetManifestFile(ManifestBuilder(this).SetPackageName("com.test").Build())
+ .AddCompiledResDir(res, &diag)
+ .AddFlag("--no-auto-version")
+ .Build(out_apk);
+ ASSERT_TRUE(Link(link_args, &diag));
+
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
+ ASSERT_THAT(apk, Ne(nullptr));
+
+ auto xml = apk->LoadXml("res/xml/locale_config.xml", &diag);
+ ASSERT_THAT(xml, NotNull());
+ EXPECT_THAT(xml->root->name, Eq("locale-config"));
+ ASSERT_THAT(xml->root->children.size(), Eq(7));
+ for (auto& node : xml->root->children) {
+ const xml::Element* child_el = xml::NodeCast<xml::Element>(node.get());
+ ASSERT_THAT(child_el, NotNull());
+ EXPECT_THAT(child_el->name, Eq("locale"));
+
+ auto& xml_attrs = child_el->attributes;
+ for (auto& attr : xml_attrs) {
+ std::string locale = "b+";
+ locale += attr.value;
+ std::replace(locale.begin(), locale.end(), '-', '+');
+ ConfigDescription config;
+ ASSERT_TRUE(ConfigDescription::Parse(locale, &config));
+ }
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index caa3e60d6af1..4033983f4c0f 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -19,18 +19,17 @@
#include <memory>
#include <vector>
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "configuration/ConfigurationParser.h"
#include "filter/AbiFilter.h"
@@ -69,7 +68,7 @@ class OptimizeContext : public IAaptContext {
return PackageType::kApp;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -130,12 +129,12 @@ class Optimizer {
int Run(std::unique_ptr<LoadedApk> apk) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK...");
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "Optimizing APK...");
}
if (!options_.resources_exclude_list.empty()) {
ResourceFilter filter(options_.resources_exclude_list);
if (!filter.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed filtering resources");
return 1;
}
}
@@ -147,20 +146,21 @@ class Optimizer {
ResourceDeduper deduper;
if (!deduper.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed deduping resources");
return 1;
}
if (options_.shorten_resource_paths) {
ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
if (!shortener.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed shortening resource paths");
return 1;
}
if (options_.shortened_paths_map_path
&& !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
options_.shortened_paths_map_path.value())) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to write shortened resource paths to file");
return 1;
}
@@ -183,9 +183,10 @@ class Optimizer {
auto split_constraints_iter = options_.split_constraints.begin();
for (std::unique_ptr<ResourceTable>& split_table : splitter.splits()) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(
- DiagMessage(*path_iter) << "generating split with configurations '"
- << util::Joiner(split_constraints_iter->configs, ", ") << "'");
+ context_->GetDiagnostics()->Note(android::DiagMessage(*path_iter)
+ << "generating split with configurations '"
+ << util::Joiner(split_constraints_iter->configs, ", ")
+ << "'");
}
// Generate an AndroidManifest.xml for each split.
@@ -228,7 +229,7 @@ class Optimizer {
private:
bool WriteSplitApk(ResourceTable* table, xml::XmlResource* manifest, IArchiveWriter* writer) {
- BigBuffer manifest_buffer(4096);
+ android::BigBuffer manifest_buffer(4096);
XmlFlattener xml_flattener(&manifest_buffer, {});
if (!xml_flattener.Consume(context_, manifest)) {
return false;
@@ -254,8 +255,8 @@ class Optimizer {
}
if (file_ref->file == nullptr) {
- ResourceNameRef name(pkg->name, type->type, entry->name);
- context_->GetDiagnostics()->Warn(DiagMessage(file_ref->GetSource())
+ ResourceNameRef name(pkg->name, type->named_type, entry->name);
+ context_->GetDiagnostics()->Warn(android::DiagMessage(file_ref->GetSource())
<< "file for resource " << name << " with config '"
<< config_value->config << "' not found");
continue;
@@ -276,7 +277,7 @@ class Optimizer {
}
}
- BigBuffer table_buffer(4096);
+ android::BigBuffer table_buffer(4096);
TableFlattener table_flattener(options_.table_flattener_options, &table_buffer);
if (!table_flattener.Consume(context_, table)) {
return false;
@@ -311,18 +312,18 @@ bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOpti
auto split_line = util::Split(line, '#');
if (split_line.size() < 2) {
- context->GetDiagnostics()->Error(DiagMessage(line) << "No # found in line");
+ context->GetDiagnostics()->Error(android::DiagMessage(line) << "No # found in line");
return false;
}
StringPiece resource_string = split_line[0];
StringPiece directives = split_line[1];
ResourceNameRef resource_name;
if (!ResourceUtils::ParseResourceName(resource_string, &resource_name)) {
- context->GetDiagnostics()->Error(DiagMessage(line) << "Malformed resource name");
+ context->GetDiagnostics()->Error(android::DiagMessage(line) << "Malformed resource name");
return false;
}
if (!resource_name.package.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(line)
+ context->GetDiagnostics()->Error(android::DiagMessage(line)
<< "Package set for resource. Only use type/name");
return false;
}
@@ -341,7 +342,7 @@ bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOpti
bool ExtractConfig(const std::string& path, IAaptContext* context, OptimizeOptions* options) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
- context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading config file");
+ context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
return false;
}
return ParseConfig(content, context, options);
@@ -356,7 +357,7 @@ bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
auto app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
if (!app_info) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to extract data from AndroidManifest.xml");
return false;
}
@@ -376,7 +377,7 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
const std::string& apk_path = args[0];
OptimizeContext context;
context.SetVerbose(verbose_);
- IDiagnostics* diag = context.GetDiagnostics();
+ android::IDiagnostics* diag = context.GetDiagnostics();
if (config_path_) {
std::string& path = config_path_.value();
@@ -384,12 +385,12 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
if (for_path) {
options_.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
if (!options_.apk_artifacts) {
- diag->Error(DiagMessage() << "Failed to parse the output artifact list");
+ diag->Error(android::DiagMessage() << "Failed to parse the output artifact list");
return 1;
}
} else {
- diag->Error(DiagMessage() << "Could not parse config file " << path);
+ diag->Error(android::DiagMessage() << "Could not parse config file " << path);
return 1;
}
@@ -411,11 +412,13 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
// Since we know that we are going to process the APK (not just print targets), make sure we
// have somewhere to write them to.
if (!options_.output_dir) {
- diag->Error(DiagMessage() << "Output directory is required when using a configuration file");
+ diag->Error(android::DiagMessage()
+ << "Output directory is required when using a configuration file");
return 1;
}
} else if (print_only_) {
- diag->Error(DiagMessage() << "Asked to print artifacts without providing a configurations");
+ diag->Error(android::DiagMessage()
+ << "Asked to print artifacts without providing a configurations");
return 1;
}
diff --git a/tools/aapt2/cmd/Optimize_test.cpp b/tools/aapt2/cmd/Optimize_test.cpp
index ac681e85b3d6..d180c87de81e 100644
--- a/tools/aapt2/cmd/Optimize_test.cpp
+++ b/tools/aapt2/cmd/Optimize_test.cpp
@@ -17,9 +17,9 @@
#include "Optimize.h"
#include "AppInfo.h"
-#include "Diagnostics.h"
#include "LoadedApk.h"
#include "Resource.h"
+#include "androidfw/IDiagnostics.h"
#include "test/Test.h"
using testing::Contains;
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 3244fb83fa4b..c3a6ed100730 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -34,10 +34,12 @@ using ::android::base::StringPrintf;
namespace aapt {
-std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) {
+std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg,
+ android::IDiagnostics* diag) {
ConfigDescription preferred_density_config;
if (!ConfigDescription::Parse(arg, &preferred_density_config)) {
- diag->Error(DiagMessage() << "invalid density '" << arg << "' for --preferred-density option");
+ diag->Error(android::DiagMessage()
+ << "invalid density '" << arg << "' for --preferred-density option");
return {};
}
@@ -46,14 +48,14 @@ std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDia
if (preferred_density_config.diff(ConfigDescription::DefaultConfig()) !=
ConfigDescription::CONFIG_DENSITY) {
- diag->Error(DiagMessage() << "invalid preferred density '" << arg << "'. "
- << "Preferred density must only be a density value");
+ diag->Error(android::DiagMessage() << "invalid preferred density '" << arg << "'. "
+ << "Preferred density must only be a density value");
return {};
}
return preferred_density_config.density;
}
-bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string* out_path,
+bool ParseSplitParameter(const StringPiece& arg, android::IDiagnostics* diag, std::string* out_path,
SplitConstraints* out_split) {
CHECK(diag != nullptr);
CHECK(out_path != nullptr);
@@ -67,9 +69,9 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
std::vector<std::string> parts = util::Split(arg, sSeparator);
if (parts.size() != 2) {
- diag->Error(DiagMessage() << "invalid split parameter '" << arg << "'");
- diag->Note(DiagMessage() << "should be --split path/to/output.apk" << sSeparator
- << "<config>[,<config>...].");
+ diag->Error(android::DiagMessage() << "invalid split parameter '" << arg << "'");
+ diag->Note(android::DiagMessage() << "should be --split path/to/output.apk" << sSeparator
+ << "<config>[,<config>...].");
return false;
}
@@ -78,8 +80,8 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
ConfigDescription config;
if (!ConfigDescription::Parse(config_str, &config)) {
- diag->Error(DiagMessage() << "invalid config '" << config_str << "' in split parameter '"
- << arg << "'");
+ diag->Error(android::DiagMessage()
+ << "invalid config '" << config_str << "' in split parameter '" << arg << "'");
return false;
}
out_split->configs.insert(config);
@@ -88,7 +90,7 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
}
std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std::string>& args,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::unique_ptr<AxisConfigFilter> filter = util::make_unique<AxisConfigFilter>();
for (const std::string& config_arg : args) {
for (const StringPiece& config_str : util::Tokenize(config_arg, ',')) {
@@ -97,12 +99,13 @@ std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std
if (lv.InitFromFilterString(config_str)) {
lv.WriteTo(&config);
} else if (!ConfigDescription::Parse(config_str, &config)) {
- diag->Error(DiagMessage() << "invalid config '" << config_str << "' for -c option");
+ diag->Error(android::DiagMessage()
+ << "invalid config '" << config_str << "' for -c option");
return {};
}
if (config.density != 0) {
- diag->Warn(DiagMessage() << "ignoring density '" << config << "' for -c option");
+ diag->Warn(android::DiagMessage() << "ignoring density '" << config << "' for -c option");
} else {
filter->AddConfig(config);
}
@@ -331,7 +334,7 @@ static std::optional<int> ExtractSdkVersion(const xml::Attribute& attr, std::str
}
std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
// Make sure the first element is <manifest> with package attribute.
const xml::Element* manifest_el = xml_res.root.get();
if (manifest_el == nullptr) {
@@ -341,20 +344,21 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
return {};
}
const xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res.file.source) << "<manifest> must have a 'package' attribute");
+ diag->Error(android::DiagMessage(xml_res.file.source)
+ << "<manifest> must have a 'package' attribute");
return {};
}
std::string error_msg;
std::optional<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
if (!maybe_package) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid package name: " << error_msg);
return {};
}
@@ -364,7 +368,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode: " << error_msg);
return {};
}
@@ -375,8 +379,8 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
- << "invalid android:versionCodeMajor: " << error_msg);
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ << "invalid android:versionCodeMajor: " << error_msg);
return {};
}
app_info.version_code_major = maybe_code.value();
@@ -386,7 +390,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode: " << error_msg);
return {};
}
@@ -397,7 +401,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
std::optional<std::string> maybe_split_name =
ExtractCompiledString(*split_name_attr, &error_msg);
if (!maybe_split_name) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid split name: " << error_msg);
return {};
}
@@ -409,7 +413,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
std::optional<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
if (!maybe_sdk) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
<< "invalid android:minSdkVersion: " << error_msg);
return {};
}
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index 1b98eb468700..7af27f57c39c 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -19,11 +19,10 @@
#include <regex>
-#include "androidfw/StringPiece.h"
-
#include "AppInfo.h"
-#include "Diagnostics.h"
#include "SdkConstants.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
#include "filter/ConfigFilter.h"
#include "split/TableSplitter.h"
#include "xml/XmlDom.h"
@@ -33,18 +32,18 @@ namespace aapt {
// Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc).
// Returns Nothing and logs a human friendly error message if the string was not legal.
std::optional<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Parses a string of the form 'path/to/output.apk:<config>[,<config>...]' and fills in
// `out_path` with the path and `out_split` with the set of ConfigDescriptions.
// Returns false and logs a human friendly error message if the string was not legal.
-bool ParseSplitParameter(const android::StringPiece& arg, IDiagnostics* diag, std::string* out_path,
- SplitConstraints* out_split);
+bool ParseSplitParameter(const android::StringPiece& arg, android::IDiagnostics* diag,
+ std::string* out_path, SplitConstraints* out_split);
// Parses a set of config filter strings of the form 'en,fr-rFR' and returns an IConfigFilter.
// Returns nullptr and logs a human friendly error message if the string was not legal.
std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std::string>& args,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Adjust the SplitConstraints so that their SDK version is stripped if it
// is less than or equal to the min_sdk. Otherwise the resources that have had
@@ -60,7 +59,7 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
// Extracts relevant info from the AndroidManifest.xml.
std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Returns a copy of 'name' which conforms to the regex '[a-zA-Z]+[a-zA-Z0-9_]*' by
// replacing nonconforming characters with underscores.
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index ac1f981d753c..91accfe0511f 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -102,7 +102,7 @@ TEST (UtilTest, LongVersionCodeUndefined) {
TEST (UtilTest, ParseSplitParameters) {
- IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
+ android::IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
std::string path;
SplitConstraints constraints;
ConfigDescription expected_configuration;
@@ -356,7 +356,7 @@ TEST (UtilTest, ParseSplitParameters) {
TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
- IDiagnostics* diagnostics = context.get()->GetDiagnostics();
+ android::IDiagnostics* diagnostics = context.get()->GetDiagnostics();
std::vector<SplitConstraints> test_constraints;
std::string path;
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index fa816be43be3..b3f98a9d3e30 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -107,10 +107,10 @@ struct IdAssignerContext {
// Returns whether the id was reserved successfully.
// Reserving identifiers must be completed before `NextId` is called for the first time.
bool ReserveId(const ResourceName& name, ResourceId id, const Visibility& visibility,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Retrieves the next available resource id that has not been reserved.
- std::optional<ResourceId> NextId(const ResourceName& name, IDiagnostics* diag);
+ std::optional<ResourceId> NextId(const ResourceName& name, android::IDiagnostics* diag);
private:
std::string package_name_;
@@ -128,7 +128,7 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- const ResourceName name(package->name, type->type, entry->name);
+ const ResourceName name(package->name, type->named_type, entry->name);
if (entry->id && !assigned_ids.ReserveId(name, entry->id.value(), entry->visibility,
context->GetDiagnostics())) {
return false;
@@ -175,7 +175,7 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- const ResourceName name(package->name, type->type, entry->name);
+ const ResourceName name(package->name, type->named_type, entry->name);
if (entry->id) {
continue;
}
@@ -267,11 +267,11 @@ Result<ResourceId> TypeGroup::NextId() {
}
bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
- const Visibility& visibility, IDiagnostics* diag) {
+ const Visibility& visibility, android::IDiagnostics* diag) {
if (package_id_ != id.package_id()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because package already has ID " << std::hex
- << (int)id.package_id());
+ diag->Error(android::DiagMessage()
+ << "can't assign ID " << id << " to resource " << name
+ << " because package already has ID " << std::hex << (int)id.package_id());
return false;
}
@@ -282,8 +282,8 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
// another type.
auto assign_result = type_id_finder_.ReserveId(key, id.type_id());
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because type " << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
+ << " because type " << assign_result.error());
return false;
}
type = types_.emplace(key, TypeGroup(package_id_, id.type_id())).first;
@@ -293,24 +293,25 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
// Ensure that non-staged resources can only exist in one type ID.
auto non_staged_type = non_staged_type_ids_.emplace(name.type.type, id.type_id());
if (!non_staged_type.second && non_staged_type.first->second != id.type_id()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because type already has ID " << std::hex
- << (int)id.type_id());
+ diag->Error(android::DiagMessage()
+ << "can't assign ID " << id << " to resource " << name
+ << " because type already has ID " << std::hex << (int)id.type_id());
return false;
}
}
auto assign_result = type->second.ReserveId(name, id);
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name << " because "
- << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
+ << " because " << assign_result.error());
return false;
}
return true;
}
-std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name, IDiagnostics* diag) {
+std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name,
+ android::IDiagnostics* diag) {
// The package name is not known during the compile stage.
// Resources without a package name are considered a part of the app being linked.
CHECK(name.package.empty() || name.package == package_name_);
@@ -331,8 +332,8 @@ std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name, ID
auto assign_result = type->second.NextId();
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign resource ID to resource " << name << " because "
- << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign resource ID to resource " << name
+ << " because " << assign_result.error());
return {};
}
return assign_result.value();
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index d3575716ae4f..8911dad39470 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -191,12 +191,12 @@ TEST_F(IdAssignerTests, ExaustEntryIdsLastIdIsPublic) {
for (auto& entry : type->entries) {
if (!entry->id) {
return ::testing::AssertionFailure()
- << "resource " << ResourceNameRef(package->name, type->type, entry->name)
+ << "resource " << ResourceNameRef(package->name, type->named_type, entry->name)
<< " has no ID";
}
if (!seen_ids.insert(entry->id.value()).second) {
return ::testing::AssertionFailure()
- << "resource " << ResourceNameRef(package->name, type->type, entry->name)
+ << "resource " << ResourceNameRef(package->name, type->named_type, entry->name)
<< " has a non-unique ID" << std::hex << entry->id.value() << std::dec;
}
}
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index de1c3bb3dd7e..444f82109de4 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -47,19 +47,19 @@ class Visitor : public xml::PackageAwareVisitor {
return;
}
- const Source src = xml_resource_->file.source.WithLine(el->line_number);
+ const android::Source src = xml_resource_->file.source.WithLine(el->line_number);
xml::Attribute* attr = el->FindAttribute({}, "name");
if (!attr) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "missing 'name' attribute");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src) << "missing 'name' attribute");
error_ = true;
return;
}
std::optional<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value);
if (!ref) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value
- << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "invalid XML attribute '" << attr->value << "'");
error_ = true;
return;
}
@@ -67,7 +67,7 @@ class Visitor : public xml::PackageAwareVisitor {
const ResourceName& name = ref.value().name.value();
std::optional<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
if (!maybe_pkg) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "invalid namespace prefix '" << name.package << "'");
error_ = true;
return;
@@ -136,15 +136,15 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
// Extracted elements must be the only child of <aapt:attr>.
// Make sure there is one root node in the children (ignore empty text).
for (std::unique_ptr<xml::Node>& child : decl.el->children) {
- const Source child_source = doc->file.source.WithLine(child->line_number);
+ const android::Source child_source = doc->file.source.WithLine(child->line_number);
if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) {
if (!util::TrimWhitespace(t->text).empty()) {
- context->GetDiagnostics()->Error(DiagMessage(child_source)
+ context->GetDiagnostics()->Error(android::DiagMessage(child_source)
<< "can't extract text into its own resource");
return false;
}
} else if (new_doc->root) {
- context->GetDiagnostics()->Error(DiagMessage(child_source)
+ context->GetDiagnostics()->Error(android::DiagMessage(child_source)
<< "inline XML resources must have a single root");
return false;
} else {
@@ -160,7 +160,7 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
// Get the parent element of <aapt:attr>
xml::Element* parent_el = decl.el->parent;
if (!parent_el) {
- context->GetDiagnostics()->Error(DiagMessage(new_doc->file.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(new_doc->file.source)
<< "no suitable parent for inheriting attribute");
return false;
}
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index d396d81d699a..76db815129dd 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -24,11 +24,10 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "trace/TraceBuffer.h"
-#include "util/BigBuffer.h"
#include "util/Util.h"
namespace aapt {
@@ -91,7 +90,7 @@ static void readDataFromStream(png_structp readPtr, png_bytep data,
static void writeDataToStream(png_structp writePtr, png_bytep data,
png_size_t length) {
- BigBuffer* outBuffer = reinterpret_cast<BigBuffer*>(png_get_io_ptr(writePtr));
+ android::BigBuffer* outBuffer = reinterpret_cast<android::BigBuffer*>(png_get_io_ptr(writePtr));
png_bytep buf = outBuffer->NextBlock<png_byte>(length);
memcpy(buf, data, length);
}
@@ -99,15 +98,15 @@ static void writeDataToStream(png_structp writePtr, png_bytep data,
static void flushDataToStream(png_structp /*writePtr*/) {}
static void logWarning(png_structp readPtr, png_const_charp warningMessage) {
- IDiagnostics* diag =
- reinterpret_cast<IDiagnostics*>(png_get_error_ptr(readPtr));
- diag->Warn(DiagMessage() << warningMessage);
+ android::IDiagnostics* diag =
+ reinterpret_cast<android::IDiagnostics*>(png_get_error_ptr(readPtr));
+ diag->Warn(android::DiagMessage() << warningMessage);
}
-static bool readPng(IDiagnostics* diag, png_structp readPtr, png_infop infoPtr,
+static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop infoPtr,
PngInfo* outInfo) {
if (setjmp(png_jmpbuf(readPtr))) {
- diag->Error(DiagMessage() << "failed reading png");
+ diag->Error(android::DiagMessage() << "failed reading png");
return false;
}
@@ -245,10 +244,9 @@ PNG_COLOR_TYPE_RGB_ALPHA) {
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(a) ((a) < 0 ? -(a) : (a))
-static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
- int grayscaleTolerance, png_colorp rgbPalette,
- png_bytep alphaPalette, int* paletteEntries,
- bool* hasTransparency, int* colorType,
+static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo,
+ int grayscaleTolerance, png_colorp rgbPalette, png_bytep alphaPalette,
+ int* paletteEntries, bool* hasTransparency, int* colorType,
png_bytepp outRows) {
int w = imageInfo.width;
int h = imageInfo.height;
@@ -383,8 +381,8 @@ static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
*colorType = PNG_COLOR_TYPE_PALETTE;
} else {
if (maxGrayDeviation <= grayscaleTolerance) {
- diag->Note(DiagMessage() << "forcing image to gray (max deviation = "
- << maxGrayDeviation << ")");
+ diag->Note(android::DiagMessage()
+ << "forcing image to gray (max deviation = " << maxGrayDeviation << ")");
*colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
} else {
*colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
@@ -431,10 +429,10 @@ static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
}
}
-static bool writePng(IDiagnostics* diag, png_structp writePtr,
- png_infop infoPtr, PngInfo* info, int grayScaleTolerance) {
+static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_infop infoPtr,
+ PngInfo* info, int grayScaleTolerance) {
if (setjmp(png_jmpbuf(writePtr))) {
- diag->Error(DiagMessage() << "failed to write png");
+ diag->Error(android::DiagMessage() << "failed to write png");
return false;
}
@@ -463,8 +461,8 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
if (kDebug) {
- diag->Note(DiagMessage() << "writing image: w = " << info->width
- << ", h = " << info->height);
+ diag->Note(android::DiagMessage()
+ << "writing image: w = " << info->width << ", h = " << info->height);
}
png_color rgbPalette[256];
@@ -486,24 +484,21 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
if (kDebug) {
switch (colorType) {
case PNG_COLOR_TYPE_PALETTE:
- diag->Note(DiagMessage() << "has " << paletteEntries << " colors"
- << (hasTransparency ? " (with alpha)" : "")
- << ", using PNG_COLOR_TYPE_PALLETTE");
+ diag->Note(android::DiagMessage() << "has " << paletteEntries << " colors"
+ << (hasTransparency ? " (with alpha)" : "")
+ << ", using PNG_COLOR_TYPE_PALLETTE");
break;
case PNG_COLOR_TYPE_GRAY:
- diag->Note(DiagMessage()
- << "is opaque gray, using PNG_COLOR_TYPE_GRAY");
+ diag->Note(android::DiagMessage() << "is opaque gray, using PNG_COLOR_TYPE_GRAY");
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- diag->Note(DiagMessage()
- << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA");
+ diag->Note(android::DiagMessage() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA");
break;
case PNG_COLOR_TYPE_RGB:
- diag->Note(DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB");
+ diag->Note(android::DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB");
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
- diag->Note(DiagMessage()
- << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA");
+ diag->Note(android::DiagMessage() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA");
break;
}
}
@@ -537,7 +532,7 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
// base 9 patch data
if (kDebug) {
- diag->Note(DiagMessage() << "adding 9-patch info..");
+ diag->Note(android::DiagMessage() << "adding 9-patch info..");
}
memcpy((char*)unknowns[pIndex].name, "npTc", 5);
unknowns[pIndex].data = (png_byte*)info->serialize9Patch();
@@ -614,11 +609,10 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
&interlaceType, &compressionType, nullptr);
if (kDebug) {
- diag->Note(DiagMessage() << "image written: w = " << width
- << ", h = " << height << ", d = " << bitDepth
- << ", colors = " << colorType
- << ", inter = " << interlaceType
- << ", comp = " << compressionType);
+ diag->Note(android::DiagMessage()
+ << "image written: w = " << width << ", h = " << height << ", d = " << bitDepth
+ << ", colors = " << colorType << ", inter = " << interlaceType
+ << ", comp = " << compressionType);
}
return true;
}
@@ -1232,20 +1226,20 @@ getout:
return true;
}
-bool Png::process(const Source& source, std::istream* input,
- BigBuffer* outBuffer, const PngOptions& options) {
+bool Png::process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
+ const PngOptions& options) {
TRACE_CALL();
png_byte signature[kPngSignatureSize];
// Read the PNG signature first.
if (!input->read(reinterpret_cast<char*>(signature), kPngSignatureSize)) {
- mDiag->Error(DiagMessage() << strerror(errno));
+ mDiag->Error(android::DiagMessage() << strerror(errno));
return false;
}
// If the PNG signature doesn't match, bail early.
if (png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- mDiag->Error(DiagMessage() << "not a valid png file");
+ mDiag->Error(android::DiagMessage() << "not a valid png file");
return false;
}
@@ -1258,13 +1252,13 @@ bool Png::process(const Source& source, std::istream* input,
readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
if (!readPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate read ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate read ptr");
goto bail;
}
infoPtr = png_create_info_struct(readPtr);
if (!infoPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate info ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate info ptr");
goto bail;
}
@@ -1281,7 +1275,7 @@ bool Png::process(const Source& source, std::istream* input,
if (util::EndsWith(source.path, ".9.png")) {
std::string errorMsg;
if (!do9Patch(&pngInfo, &errorMsg)) {
- mDiag->Error(DiagMessage() << errorMsg);
+ mDiag->Error(android::DiagMessage() << errorMsg);
goto bail;
}
}
@@ -1289,13 +1283,13 @@ bool Png::process(const Source& source, std::istream* input,
writePtr =
png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
if (!writePtr) {
- mDiag->Error(DiagMessage() << "failed to allocate write ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate write ptr");
goto bail;
}
writeInfoPtr = png_create_info_struct(writePtr);
if (!writeInfoPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate write info ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate write info ptr");
goto bail;
}
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index 7ca1f0ec7800..7f8d923edd03 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -21,13 +21,12 @@
#include <string>
#include "android-base/macros.h"
-
-#include "Diagnostics.h"
-#include "Source.h"
+#include "androidfw/BigBuffer.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "compile/Image.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
namespace aapt {
@@ -43,15 +42,16 @@ struct PngOptions {
*/
class Png {
public:
- explicit Png(IDiagnostics* diag) : mDiag(diag) {}
+ explicit Png(android::IDiagnostics* diag) : mDiag(diag) {
+ }
- bool process(const Source& source, std::istream* input, BigBuffer* outBuffer,
+ bool process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
const PngOptions& options);
private:
DISALLOW_COPY_AND_ASSIGN(Png);
- IDiagnostics* mDiag;
+ android::IDiagnostics* mDiag;
};
/**
@@ -90,7 +90,8 @@ class PngChunkFilter : public io::InputStream {
/**
* Reads a PNG from the InputStream into memory as an RGBA Image.
*/
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in);
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
+ io::InputStream* in);
/**
* Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
index 1f4ea44d9f86..4ef87ba3671b 100644
--- a/tools/aapt2/compile/PngCrunch.cpp
+++ b/tools/aapt2/compile/PngCrunch.cpp
@@ -67,14 +67,14 @@ class PngWriteStructDeleter {
// Custom warning logging method that uses IDiagnostics.
static void LogWarning(png_structp png_ptr, png_const_charp warning_msg) {
- IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Warn(DiagMessage() << warning_msg);
+ android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
+ diag->Warn(android::DiagMessage() << warning_msg);
}
// Custom error logging method that uses IDiagnostics.
static void LogError(png_structp png_ptr, png_const_charp error_msg) {
- IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Error(DiagMessage() << error_msg);
+ android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
+ diag->Error(android::DiagMessage() << error_msg);
// Causes libpng to longjmp to the spot where setjmp was set. This is how libpng does
// error handling. If this custom error handler method were to return, libpng would, by
@@ -143,10 +143,11 @@ static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t
}
}
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in) {
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
+ io::InputStream* in) {
TRACE_CALL();
// Create a diagnostics that has the source information encoded.
- SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
+ android::SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
// Read the first 8 bytes of the file looking for the PNG signature.
// Bail early if it does not match.
@@ -154,15 +155,16 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
size_t buffer_size;
if (!in->Next((const void**)&signature, &buffer_size)) {
if (in->HadError()) {
- source_diag.Error(DiagMessage() << "failed to read PNG signature: " << in->GetError());
+ source_diag.Error(android::DiagMessage()
+ << "failed to read PNG signature: " << in->GetError());
} else {
- source_diag.Error(DiagMessage() << "not enough data for PNG signature");
+ source_diag.Error(android::DiagMessage() << "not enough data for PNG signature");
}
return {};
}
if (buffer_size < kPngSignatureSize || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- source_diag.Error(DiagMessage() << "file signature does not match PNG signature");
+ source_diag.Error(android::DiagMessage() << "file signature does not match PNG signature");
return {};
}
@@ -174,14 +176,14 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
// version of libpng.
png_structp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (read_ptr == nullptr) {
- source_diag.Error(DiagMessage() << "failed to create libpng read png_struct");
+ source_diag.Error(android::DiagMessage() << "failed to create libpng read png_struct");
return {};
}
// Create and initialize the memory for image header and data.
png_infop info_ptr = png_create_info_struct(read_ptr);
if (info_ptr == nullptr) {
- source_diag.Error(DiagMessage() << "failed to create libpng read png_info");
+ source_diag.Error(android::DiagMessage() << "failed to create libpng read png_info");
png_destroy_read_struct(&read_ptr, nullptr, nullptr);
return {};
}
@@ -254,7 +256,7 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
// something
// that can always be represented by 9-patch.
if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) {
- source_diag.Error(DiagMessage()
+ source_diag.Error(android::DiagMessage()
<< "PNG image dimensions are too large: " << width << "x" << height);
return {};
}
@@ -490,14 +492,16 @@ bool WritePng(IAaptContext* context, const Image* image,
// version of libpng.
png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (write_ptr == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_struct");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create libpng write png_struct");
return false;
}
// Allocate memory to store image header data.
png_infop write_info_ptr = png_create_info_struct(write_ptr);
if (write_info_ptr == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_info");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create libpng write png_info");
png_destroy_write_struct(&write_ptr, nullptr);
return false;
}
@@ -575,7 +579,7 @@ bool WritePng(IAaptContext* context, const Image* image,
}
if (context->IsVerbose()) {
- DiagMessage msg;
+ android::DiagMessage msg;
msg << " paletteSize=" << color_palette.size()
<< " alphaPaletteSize=" << alpha_palette.size()
<< " maxGrayDeviation=" << max_gray_deviation
@@ -590,7 +594,7 @@ bool WritePng(IAaptContext* context, const Image* image,
nine_patch != nullptr, color_palette.size(), alpha_palette.size());
if (context->IsVerbose()) {
- DiagMessage msg;
+ android::DiagMessage msg;
msg << "encoding PNG ";
if (nine_patch) {
msg << "(with 9-patch) as ";
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 2461438c49b6..09a8560f984a 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -21,6 +21,7 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "androidfw/Util.h"
#include "compile/Pseudolocalizer.h"
#include "util/Util.h"
@@ -53,7 +54,7 @@ inline static bool operator<(const UnifiedSpan& left, const UnifiedSpan& right)
return false;
}
-inline static UnifiedSpan SpanToUnifiedSpan(const StringPool::Span& span) {
+inline static UnifiedSpan SpanToUnifiedSpan(const android::StringPool::Span& span) {
return UnifiedSpan{*span.name, span.first_char, span.last_char};
}
@@ -111,7 +112,7 @@ static std::vector<UnifiedSpan> MergeSpans(const StyledString& string) {
std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
Pseudolocalizer::Method method,
- StringPool* pool) {
+ android::StringPool* pool) {
Pseudolocalizer localizer(method);
// Collect the spans and untranslatable sections into one set of spans, sorted by first_char.
@@ -121,7 +122,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
// All Span indices are UTF-16 based, according to the resources.arsc format expected by the
// runtime. So we will do all our processing in UTF-16, then convert back.
- const std::u16string text16 = util::Utf8ToUtf16(string->value->value);
+ const std::u16string text16 = android::util::Utf8ToUtf16(string->value->value);
// Convenient wrapper around the text that allows us to work with StringPieces.
const StringPiece16 text(text16);
@@ -154,7 +155,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
cursor += substr.size();
// Pseudolocalize the substring.
- std::string new_substr = util::Utf16ToUtf8(substr);
+ std::string new_substr = android::util::Utf16ToUtf8(substr);
if (translatable) {
new_substr = localizer.Text(new_substr);
}
@@ -181,7 +182,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
cursor += substr.size();
// Pseudolocalize the substring.
- std::string new_substr = util::Utf16ToUtf8(substr);
+ std::string new_substr = android::util::Utf16ToUtf8(substr);
if (translatable) {
new_substr = localizer.Text(new_substr);
}
@@ -199,16 +200,18 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
}
// Finish the pseudolocalization at the end of the string.
- new_string += localizer.Text(util::Utf16ToUtf8(text.substr(cursor, text.size() - cursor)));
+ new_string +=
+ localizer.Text(android::util::Utf16ToUtf8(text.substr(cursor, text.size() - cursor)));
new_string += localizer.End();
- StyleString localized;
+ android::StyleString localized;
localized.str = std::move(new_string);
// Convert the UnifiedSpans into regular Spans, skipping the UntranslatableSections.
for (UnifiedSpan& span : merged_spans) {
if (span.tag) {
- localized.spans.push_back(Span{std::move(span.tag.value()), span.first_char, span.last_char});
+ localized.spans.push_back(
+ android::Span{std::move(span.tag.value()), span.first_char, span.last_char});
}
}
return util::make_unique<StyledString>(pool->MakeRef(localized));
@@ -222,8 +225,9 @@ class Visitor : public ValueVisitor {
std::unique_ptr<Value> value;
std::unique_ptr<Item> item;
- Visitor(StringPool* pool, Pseudolocalizer::Method method)
- : pool_(pool), method_(method), localizer_(method) {}
+ Visitor(android::StringPool* pool, Pseudolocalizer::Method method)
+ : pool_(pool), method_(method), localizer_(method) {
+ }
void Visit(Plural* plural) override {
CloningValueTransformer cloner(pool_);
@@ -284,7 +288,7 @@ class Visitor : public ValueVisitor {
private:
DISALLOW_COPY_AND_ASSIGN(Visitor);
- StringPool* pool_;
+ android::StringPool* pool_;
Pseudolocalizer::Method method_;
Pseudolocalizer localizer_;
};
@@ -313,8 +317,8 @@ ConfigDescription ModifyConfigForPseudoLocale(const ConfigDescription& base,
}
void PseudolocalizeIfNeeded(const Pseudolocalizer::Method method,
- ResourceConfigValue* original_value,
- StringPool* pool, ResourceEntry* entry) {
+ ResourceConfigValue* original_value, android::StringPool* pool,
+ ResourceEntry* entry) {
Visitor visitor(pool, method);
original_value->value->Accept(&visitor);
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h
index ace378603f65..44e6e3e86f92 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.h
+++ b/tools/aapt2/compile/PseudolocaleGenerator.h
@@ -17,14 +17,15 @@
#ifndef AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
#include "compile/Pseudolocalizer.h"
#include "process/IResourceTableConsumer.h"
namespace aapt {
-std::unique_ptr<StyledString> PseudolocalizeStyledString(
- StyledString* string, Pseudolocalizer::Method method, StringPool* pool);
+std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ android::StringPool* pool);
struct PseudolocaleGenerator : public IResourceTableConsumer {
bool Consume(IAaptContext* context, ResourceTable* table) override;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
index 432d7bfdad49..2f90cbf722c2 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -24,10 +24,11 @@ using ::android::ConfigDescription;
namespace aapt {
TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "Hello world!";
- original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}};
+ original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
+ android::Span{"b", 6, 7}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -48,7 +49,7 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
EXPECT_EQ(std::u16string(u"Hello ").size(), new_string->value->spans[2].first_char);
EXPECT_EQ(std::u16string(u"Hello w").size(), new_string->value->spans[2].last_char);
- original_style.spans.insert(original_style.spans.begin(), Span{"em", 0, 11u});
+ original_style.spans.insert(original_style.spans.begin(), android::Span{"em", 0, 11u});
new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -71,10 +72,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "bold";
- original_style.spans = {Span{"b", 0, 3}, Span{"i", 0, 3}};
+ original_style.spans = {android::Span{"b", 0, 3}, android::Span{"i", 0, 3}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -93,10 +94,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "bold";
- original_style.spans = {Span{"i", 2, 3}, Span{"b", 0, 1}};
+ original_style.spans = {android::Span{"i", 2, 3}, android::Span{"b", 0, 1}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -115,11 +116,11 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "This sentence is not what you think it is at all.";
- original_style.spans = {Span{"b", 16u, 19u}, Span{"em", 29u, 47u}, Span{"i", 38u, 40u},
- Span{"b", 44u, 47u}};
+ original_style.spans = {android::Span{"b", 16u, 19u}, android::Span{"em", 29u, 47u},
+ android::Span{"i", 38u, 40u}, android::Span{"b", 44u, 47u}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -154,10 +155,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizePartsOfString) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "This should NOT be pseudolocalized.";
- original_style.spans = {Span{"em", 4u, 14u}, Span{"i", 18u, 33u}};
+ original_style.spans = {android::Span{"em", 4u, 14u}, android::Span{"i", 18u, 33u}};
std::unique_ptr<StyledString> original_string =
util::make_unique<StyledString>(pool.MakeRef(original_style));
original_string->untranslatable_sections = {UntranslatableSection{11u, 15u}};
@@ -263,9 +264,10 @@ TEST(PseudolocaleGeneratorTest, RespectUntranslateableSections) {
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
{
- StyleString original_style;
+ android::StyleString original_style;
original_style.str = "Hello world!";
- original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}};
+ original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
+ android::Span{"b", 6, 7}};
auto styled_string =
util::make_unique<StyledString>(table->string_pool.MakeRef(original_style));
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
index 6cf003b24157..4dedc700a8e7 100644
--- a/tools/aapt2/compile/Pseudolocalizer.h
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -19,11 +19,10 @@
#include <memory>
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
-
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp
index bb72159f9e77..68cb36a078dd 100644
--- a/tools/aapt2/compile/XmlIdCollector.cpp
+++ b/tools/aapt2/compile/XmlIdCollector.cpp
@@ -38,8 +38,9 @@ struct IdCollector : public xml::Visitor {
using xml::Visitor::Visit;
explicit IdCollector(std::vector<SourcedResourceName>* out_symbols,
- SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols),
- source_diag_(source_diag) {}
+ android::SourcePathDiagnostics* source_diag)
+ : out_symbols_(out_symbols), source_diag_(source_diag) {
+ }
void Visit(xml::Element* element) override {
for (xml::Attribute& attr : element->attributes) {
@@ -48,8 +49,8 @@ struct IdCollector : public xml::Visitor {
if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) {
if (create && name.type.type == ResourceType::kId) {
if (!text::IsValidResourceEntryName(name.entry)) {
- source_diag_->Error(DiagMessage(element->line_number)
- << "id '" << name << "' has an invalid entry name");
+ source_diag_->Error(android::DiagMessage(element->line_number)
+ << "id '" << name << "' has an invalid entry name");
} else {
auto iter = std::lower_bound(out_symbols_->begin(),
out_symbols_->end(), name, cmp_name);
@@ -67,7 +68,7 @@ struct IdCollector : public xml::Visitor {
private:
std::vector<SourcedResourceName>* out_symbols_;
- SourcePathDiagnostics* source_diag_;
+ android::SourcePathDiagnostics* source_diag_;
};
} // namespace
@@ -75,7 +76,7 @@ struct IdCollector : public xml::Visitor {
bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) {
TRACE_CALL();
xmlRes->file.exported_symbols.clear();
- SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
+ android::SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
IdCollector collector(&xmlRes->file.exported_symbols, &source_diag);
xmlRes->root->Accept(&collector);
return !source_diag.HadError();
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index e7a45851e239..6bba11e26e6a 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -23,12 +23,11 @@
#include <string>
#include <utility>
+#include "ResourceUtils.h"
#include "android-base/file.h"
#include "android-base/logging.h"
#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
-#include "ResourceUtils.h"
+#include "androidfw/IDiagnostics.h"
#include "configuration/ConfigurationParser.internal.h"
#include "io/File.h"
#include "io/FileSystem.h"
@@ -88,15 +87,10 @@ const std::array<StringPiece, 8> kAbiToStringMap = {
constexpr const char* kAaptXmlNs = "http://schemas.android.com/tools/aapt";
-/** A default noop diagnostics context. */
-class NoopDiagnostics : public IDiagnostics {
- public:
- void Log(Level level, DiagMessageActual& actualMsg) override {}
-};
-NoopDiagnostics noop_;
+android::NoOpDiagnostics noop_;
/** Returns the value of the label attribute for a given element. */
-std::string GetLabel(const Element* element, IDiagnostics* diag) {
+std::string GetLabel(const Element* element, android::IDiagnostics* diag) {
std::string label;
for (const auto& attr : element->attributes) {
if (attr.name == "label") {
@@ -106,18 +100,18 @@ std::string GetLabel(const Element* element, IDiagnostics* diag) {
}
if (label.empty()) {
- diag->Error(DiagMessage() << "No label found for element " << element->name);
+ diag->Error(android::DiagMessage() << "No label found for element " << element->name);
}
return label;
}
/** Returns the value of the version-code-order attribute for a given element. */
-std::optional<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+std::optional<int32_t> GetVersionCodeOrder(const Element* element, android::IDiagnostics* diag) {
const xml::Attribute* version = element->FindAttribute("", "version-code-order");
if (version == nullptr) {
std::string label = GetLabel(element, diag);
- diag->Error(DiagMessage() << "No version-code-order found for element '" << element->name
- << "' with label '" << label << "'");
+ diag->Error(android::DiagMessage() << "No version-code-order found for element '"
+ << element->name << "' with label '" << label << "'");
return {};
}
return std::stoi(version->value);
@@ -159,14 +153,14 @@ bool CopyXmlReferences(const std::optional<std::string>& name, const Group<T>& g
* present and the placeholder was.
*/
bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<StringPiece>& value,
- std::string* name, IDiagnostics* diag) {
+ std::string* name, android::IDiagnostics* diag) {
size_t offset = name->find(placeholder.data());
bool found = (offset != std::string::npos);
// Make sure the placeholder was present if the desired value is present.
if (!found) {
if (value) {
- diag->Error(DiagMessage() << "Missing placeholder for artifact: " << placeholder);
+ diag->Error(android::DiagMessage() << "Missing placeholder for artifact: " << placeholder);
return false;
}
return true;
@@ -176,7 +170,8 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
// Make sure the placeholder was not present if the desired value was not present.
if (!value) {
- diag->Error(DiagMessage() << "Placeholder present but no value for artifact: " << placeholder);
+ diag->Error(android::DiagMessage()
+ << "Placeholder present but no value for artifact: " << placeholder);
return false;
}
@@ -184,7 +179,7 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
// Make sure there was only one instance of the placeholder.
if (name->find(placeholder.data()) != std::string::npos) {
- diag->Error(DiagMessage() << "Placeholder present multiple times: " << placeholder);
+ diag->Error(android::DiagMessage() << "Placeholder present multiple times: " << placeholder);
return false;
}
return true;
@@ -195,12 +190,12 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
* element was successfully processed, otherwise returns false.
*/
using ActionHandler = std::function<bool(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag)>;
+ xml::Element* element, android::IDiagnostics* diag)>;
/** Binds an ActionHandler to the current configuration being populated. */
xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfiguration* config,
const ActionHandler& handler) {
- return [config, handler](xml::Element* root_element, SourcePathDiagnostics* diag) {
+ return [config, handler](xml::Element* root_element, android::SourcePathDiagnostics* diag) {
return handler(config, root_element, diag);
};
}
@@ -209,10 +204,10 @@ xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfigu
std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact,
const std::string& apk_name,
const PostProcessingConfiguration& config,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
if (!artifact.name && !config.artifact_format) {
- diag->Error(
- DiagMessage() << "Artifact does not have a name and no global name template defined");
+ diag->Error(android::DiagMessage()
+ << "Artifact does not have a name and no global name template defined");
return {};
}
@@ -221,54 +216,54 @@ std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifac
: artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag);
if (!artifact_name) {
- diag->Error(DiagMessage() << "Could not determine split APK artifact name");
+ diag->Error(android::DiagMessage() << "Could not determine split APK artifact name");
return {};
}
OutputArtifact output_artifact;
output_artifact.name = artifact_name.value();
- SourcePathDiagnostics src_diag{{output_artifact.name}, diag};
+ android::SourcePathDiagnostics src_diag{{output_artifact.name}, diag};
bool has_errors = false;
if (!CopyXmlReferences(artifact.abi_group, config.abi_groups, &output_artifact.abis)) {
- src_diag.Error(DiagMessage() << "Could not lookup required ABIs: "
- << artifact.abi_group.value());
+ src_diag.Error(android::DiagMessage()
+ << "Could not lookup required ABIs: " << artifact.abi_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.locale_group, config.locale_groups, &output_artifact.locales)) {
- src_diag.Error(DiagMessage() << "Could not lookup required locales: "
- << artifact.locale_group.value());
+ src_diag.Error(android::DiagMessage()
+ << "Could not lookup required locales: " << artifact.locale_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.screen_density_group, config.screen_density_groups,
&output_artifact.screen_densities)) {
- src_diag.Error(DiagMessage() << "Could not lookup required screen densities: "
- << artifact.screen_density_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required screen densities: "
+ << artifact.screen_density_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.device_feature_group, config.device_feature_groups,
&output_artifact.features)) {
- src_diag.Error(DiagMessage() << "Could not lookup required device features: "
- << artifact.device_feature_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required device features: "
+ << artifact.device_feature_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.gl_texture_group, config.gl_texture_groups,
&output_artifact.textures)) {
- src_diag.Error(DiagMessage() << "Could not lookup required OpenGL texture formats: "
- << artifact.gl_texture_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required OpenGL texture formats: "
+ << artifact.gl_texture_group.value());
has_errors = true;
}
if (artifact.android_sdk) {
auto entry = config.android_sdks.find(artifact.android_sdk.value());
if (entry == config.android_sdks.end()) {
- src_diag.Error(DiagMessage() << "Could not lookup required Android SDK version: "
- << artifact.android_sdk.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required Android SDK version: "
+ << artifact.android_sdk.value());
has_errors = true;
} else {
output_artifact.android_sdk = {entry->second};
@@ -288,9 +283,9 @@ namespace configuration {
/** Returns the binary reprasentation of the XML configuration. */
std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
const std::string& config_path,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
StringInputStream in(contents);
- std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, Source(config_path));
+ std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, android::Source(config_path));
if (!doc) {
return {};
}
@@ -298,14 +293,14 @@ std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::strin
// Strip any namespaces from the XML as the XmlActionExecutor ignores anything with a namespace.
Element* root = doc->root.get();
if (root == nullptr) {
- diag->Error(DiagMessage() << "Could not find the root element in the XML document");
+ diag->Error(android::DiagMessage() << "Could not find the root element in the XML document");
return {};
}
std::string& xml_ns = root->namespace_uri;
if (!xml_ns.empty()) {
if (xml_ns != kAaptXmlNs) {
- diag->Error(DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
+ diag->Error(android::DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
return {};
}
@@ -336,7 +331,7 @@ std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::strin
Bind(&config, DeviceFeatureGroupTagHandler));
if (!executor.Execute(XmlActionExecutorPolicy::kNone, diag, doc.get())) {
- diag->Error(DiagMessage() << "Could not process XML document");
+ diag->Error(android::DiagMessage() << "Could not process XML document");
return {};
}
@@ -351,7 +346,7 @@ const StringPiece& AbiToString(Abi abi) {
* Returns the common artifact base name from a template string.
*/
std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk_name,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
const StringPiece ext = file::GetExtension(apk_name);
size_t end_index = apk_name.to_string().rfind(ext.to_string());
const std::string base_name =
@@ -385,7 +380,7 @@ std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk
std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
const StringPiece& apk_name,
- IDiagnostics* diag) const {
+ android::IDiagnostics* diag) const {
std::optional<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
if (!base) {
return {};
@@ -420,7 +415,7 @@ std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece&
}
std::optional<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name,
- IDiagnostics* diag) const {
+ android::IDiagnostics* diag) const {
if (!name) {
return {};
}
@@ -473,7 +468,7 @@ std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
}
if (!config.ValidateVersionCodeOrdering(diag_)) {
- diag_->Error(DiagMessage() << "could not validate post processing configuration");
+ diag_->Error(android::DiagMessage() << "could not validate post processing configuration");
valid = false;
}
@@ -493,7 +488,7 @@ namespace configuration {
namespace handler {
bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
ConfiguredArtifact artifact{};
for (const auto& attr : root_element->attributes) {
if (attr.name == "name") {
@@ -511,8 +506,8 @@ bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_eleme
} else if (attr.name == "device-feature-group") {
artifact.device_feature_group = {attr.value};
} else {
- diag->Note(DiagMessage() << "Unknown artifact attribute: " << attr.name << " = "
- << attr.value);
+ diag->Note(android::DiagMessage()
+ << "Unknown artifact attribute: " << attr.name << " = " << attr.value);
}
}
config->artifacts.push_back(artifact);
@@ -520,7 +515,7 @@ bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_eleme
};
bool ArtifactFormatTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* /* diag */) {
+ android::IDiagnostics* /* diag */) {
for (auto& node : root_element->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
@@ -532,7 +527,7 @@ bool ArtifactFormatTagHandler(PostProcessingConfiguration* config, Element* root
};
bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -560,7 +555,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
for (auto* child : root_element->GetChildElements()) {
if (child->name != "abi") {
- diag->Error(DiagMessage() << "Unexpected element in ABI group: " << child->name);
+ diag->Error(android::DiagMessage() << "Unexpected element in ABI group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
@@ -570,7 +565,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
if (abi != kStringToAbiMap.end()) {
group.push_back(abi->second);
} else {
- diag->Error(DiagMessage() << "Could not parse ABI value: " << t->text);
+ diag->Error(android::DiagMessage() << "Could not parse ABI value: " << t->text);
valid = false;
}
break;
@@ -583,7 +578,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
};
bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -609,9 +604,8 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
// Copy the density with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
- << "Could not parse config descriptor for empty screen-density-group: "
- << label);
+ diag->Error(android::DiagMessage()
+ << "Could not parse config descriptor for empty screen-density-group: " << label);
valid = false;
}
@@ -620,8 +614,8 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
for (auto* child : root_element->GetChildElements()) {
if (child->name != "screen-density") {
- diag->Error(DiagMessage() << "Unexpected root_element in screen density group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in screen density group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
@@ -636,7 +630,7 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
// Copy the density with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "Could not parse config descriptor for screen-density: " << text);
valid = false;
}
@@ -650,7 +644,7 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
};
bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -676,9 +670,8 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
// Copy the locale with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
- << "Could not parse config descriptor for empty screen-density-group: "
- << label);
+ diag->Error(android::DiagMessage()
+ << "Could not parse config descriptor for empty screen-density-group: " << label);
valid = false;
}
@@ -687,8 +680,8 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
for (auto* child : root_element->GetChildElements()) {
if (child->name != "locale") {
- diag->Error(DiagMessage() << "Unexpected root_element in screen density group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in screen density group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
@@ -703,7 +696,7 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
// Copy the locale with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "Could not parse config descriptor for screen-density: " << text);
valid = false;
}
@@ -717,7 +710,7 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
};
bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
AndroidSdk entry = AndroidSdk::ForMinSdk(-1);
bool valid = true;
for (const auto& attr : root_element->attributes) {
@@ -746,13 +739,14 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
}
if (!valid_attr) {
- diag->Error(DiagMessage() << "Invalid attribute: " << attr.name << " = " << attr.value);
+ diag->Error(android::DiagMessage()
+ << "Invalid attribute: " << attr.name << " = " << attr.value);
valid = false;
}
}
if (entry.min_sdk_version == -1) {
- diag->Error(DiagMessage() << "android-sdk is missing minSdkVersion attribute");
+ diag->Error(android::DiagMessage() << "android-sdk is missing minSdkVersion attribute");
valid = false;
}
@@ -760,7 +754,7 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
for (auto node : root_element->GetChildElements()) {
if (node->name == "manifest") {
if (entry.manifest) {
- diag->Warn(DiagMessage() << "Found multiple manifest tags. Ignoring duplicates.");
+ diag->Warn(android::DiagMessage() << "Found multiple manifest tags. Ignoring duplicates.");
continue;
}
entry.manifest = {AndroidManifest()};
@@ -772,7 +766,7 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
};
bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -791,7 +785,8 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
GlTexture result;
for (auto* child : root_element->GetChildElements()) {
if (child->name != "gl-texture") {
- diag->Error(DiagMessage() << "Unexpected element in GL texture group: " << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected element in GL texture group: " << child->name);
valid = false;
} else {
for (const auto& attr : child->attributes) {
@@ -803,7 +798,8 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
for (auto* element : child->GetChildElements()) {
if (element->name != "texture-path") {
- diag->Error(DiagMessage() << "Unexpected element in gl-texture element: " << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected element in gl-texture element: " << child->name);
valid = false;
continue;
}
@@ -822,7 +818,7 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
};
bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -840,8 +836,8 @@ bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element*
for (auto* child : root_element->GetChildElements()) {
if (child->name != "supports-feature") {
- diag->Error(DiagMessage() << "Unexpected root_element in device feature group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in device feature group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 195b4baac319..2c8221d5108b 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -24,8 +24,7 @@
#include <vector>
#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
namespace aapt {
@@ -126,9 +125,6 @@ struct OutputArtifact {
} // namespace configuration
-// Forward declaration of classes used in the API.
-struct IDiagnostics;
-
/**
* XML configuration file parser for the split and optimize commands.
*/
@@ -145,7 +141,7 @@ class ConfigurationParser {
}
/** Sets the diagnostics context to use when parsing. */
- ConfigurationParser& WithDiagnostics(IDiagnostics* diagnostics) {
+ ConfigurationParser& WithDiagnostics(android::IDiagnostics* diagnostics) {
diag_ = diagnostics;
return *this;
}
@@ -166,7 +162,7 @@ class ConfigurationParser {
ConfigurationParser(std::string contents, const std::string& config_path);
/** Returns the current diagnostics context to any subclasses. */
- IDiagnostics* diagnostics() {
+ android::IDiagnostics* diagnostics() {
return diag_;
}
@@ -176,7 +172,7 @@ class ConfigurationParser {
/** Path to the input configuration. */
const std::string config_path_;
/** The diagnostics context to send messages to. */
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
} // namespace aapt
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index 42ef51591d4f..3028c3f58e4e 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -47,15 +47,16 @@ using Entry = std::unordered_map<std::string, T>;
template <class T>
using Group = Entry<OrderedEntry<T>>;
-template<typename T>
-bool IsGroupValid(const Group<T>& group, const std::string& name, IDiagnostics* diag) {
+template <typename T>
+bool IsGroupValid(const Group<T>& group, const std::string& name, android::IDiagnostics* diag) {
std::set<int32_t> orders;
for (const auto& p : group) {
orders.insert(p.second.order);
}
bool valid = orders.size() == group.size();
if (!valid) {
- diag->Error(DiagMessage() << name << " have overlapping version-code-order attributes");
+ diag->Error(android::DiagMessage()
+ << name << " have overlapping version-code-order attributes");
}
return valid;
}
@@ -139,10 +140,11 @@ struct ConfiguredArtifact {
/** Convert an artifact name template into a name string based on configuration contents. */
std::optional<std::string> ToArtifactName(const android::StringPiece& format,
const android::StringPiece& apk_name,
- IDiagnostics* diag) const;
+ android::IDiagnostics* diag) const;
/** Convert an artifact name template into a name string based on configuration contents. */
- std::optional<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
+ std::optional<std::string> Name(const android::StringPiece& apk_name,
+ android::IDiagnostics* diag) const;
};
/** AAPT2 XML configuration file binary representation. */
@@ -157,7 +159,7 @@ struct PostProcessingConfiguration {
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
- bool ValidateVersionCodeOrdering(IDiagnostics* diag) {
+ bool ValidateVersionCodeOrdering(android::IDiagnostics* diag) {
bool valid = IsGroupValid(abi_groups, "abi-groups", diag);
valid &= IsGroupValid(screen_density_groups, "screen-density-groups", diag);
valid &= IsGroupValid(locale_groups, "locale-groups", diag);
@@ -215,41 +217,41 @@ struct PostProcessingConfiguration {
/** Parses the provided XML document returning the post processing configuration. */
std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
const std::string& config_path,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
namespace handler {
/** Handler for <artifact> tags. */
bool ArtifactTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <artifact-format> tags. */
bool ArtifactFormatTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <abi-group> tags. */
bool AbiGroupTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <screen-density-group> tags. */
bool ScreenDensityGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <locale-group> tags. */
bool LocaleGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <android-sdk> tags. */
bool AndroidSdkTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <gl-texture-group> tags. */
bool GlTextureGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <device-feature-group> tags. */
bool DeviceFeatureGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
} // namespace handler
} // namespace configuration
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 9828b97982ed..39ac24b29f35 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -17,17 +17,21 @@
#include "DumpManifest.h"
#include <algorithm>
+#include <array>
+#include <memory>
+#include <set>
+#include <string_view>
+#include <vector>
#include "LoadedApk.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "androidfw/ConfigDescription.h"
#include "io/File.h"
#include "io/FileStream.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
-#include "androidfw/ConfigDescription.h"
-
using ::android::base::StringPrintf;
using ::android::ConfigDescription;
@@ -112,7 +116,101 @@ static xml::Attribute* FindAttribute(xml::Element *el, const std::string &packag
return el->FindAttribute(package, name);
}
+class Architectures {
+ public:
+ std::set<std::string> architectures;
+ std::set<std::string> alt_architectures;
+
+ void Print(text::Printer* printer) {
+ if (!architectures.empty()) {
+ printer->Print("native-code:");
+ for (auto& arch : architectures) {
+ printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ printer->Print("\n");
+ }
+ if (!alt_architectures.empty()) {
+ printer->Print("alt-native-code:");
+ for (auto& arch : alt_architectures) {
+ printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ printer->Print("\n");
+ }
+ }
+
+ void ToProto(pb::Badging* out_badging) {
+ auto out_architectures = out_badging->mutable_architectures();
+ for (auto& arch : architectures) {
+ out_architectures->add_architectures(arch);
+ }
+ for (auto& arch : alt_architectures) {
+ out_architectures->add_alt_architectures(arch);
+ }
+ }
+};
+
+const static std::array<std::string_view, 14> printable_components{"app-widget",
+ "device-admin",
+ "ime",
+ "wallpaper",
+ "accessibility",
+ "print-service",
+ "payment",
+ "search",
+ "document-provider",
+ "launcher",
+ "notification-listener",
+ "dream",
+ "camera",
+ "camera-secure"};
+
+class Components {
+ public:
+ std::set<std::string, std::less<>> discovered_components;
+ bool other_activities = false;
+ bool other_receivers = false;
+ bool other_services = false;
+
+ void Print(text::Printer* printer) {
+ for (auto& component : printable_components) {
+ if (discovered_components.find(component) != discovered_components.end()) {
+ printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
+ }
+ }
+ // Print presence of main activity
+ if (discovered_components.find("main") != discovered_components.end()) {
+ printer->Print("main\n");
+ }
+
+ if (other_activities) {
+ printer->Print("other-activities\n");
+ }
+ if (other_receivers) {
+ printer->Print("other-receivers\n");
+ }
+ if (other_services) {
+ printer->Print("other-services\n");
+ }
+ }
+
+ void ToProto(pb::Badging* out_badging) {
+ auto out_components = out_badging->mutable_components();
+ for (auto& component : printable_components) {
+ auto discovered = discovered_components.find(component);
+ if (discovered != discovered_components.end()) {
+ out_components->add_provided_components(*discovered);
+ }
+ }
+ out_components->set_main(discovered_components.find("main") != discovered_components.end());
+ out_components->set_other_activities(other_activities);
+ out_components->set_other_receivers(other_receivers);
+ out_components->set_other_services(other_services);
+ }
+};
+
class CommonFeatureGroup;
+class FeatureGroup;
+class SupportsScreen;
class ManifestExtractor {
public:
@@ -128,7 +226,12 @@ class ManifestExtractor {
static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
/** Writes out the extracted contents of the element. */
- virtual void Print(text::Printer* printer) { }
+ virtual void Print(text::Printer* printer) {
+ }
+
+ /** Saves extracted information into Badging proto. */
+ virtual void ToProto(pb::Badging* out_badging) {
+ }
/** Adds an element to the list of children of the element. */
void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
@@ -338,7 +441,9 @@ class ManifestExtractor {
return config;
}
- bool Dump(text::Printer* printer, IDiagnostics* diag);
+ bool Extract(android::IDiagnostics* diag);
+ bool Dump(text::Printer* printer);
+ bool DumpProto(pb::Badging* out_badging);
/** Recursively visit the xml element tree and return a processed badging element tree. */
std::unique_ptr<Element> Visit(xml::Element* element);
@@ -354,7 +459,7 @@ class ManifestExtractor {
* Retrieves the default feature group that features are added into when <uses-feature>
* are not in a <feature-group> element.
**/
- CommonFeatureGroup* GetCommonFeatureGroup() {
+ CommonFeatureGroup* common_feature_group() {
return commonFeatureGroup_.get();
}
@@ -387,11 +492,19 @@ class ManifestExtractor {
DumpManifestOptions& options_;
private:
+ std::unique_ptr<xml::XmlResource> doc_;
std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
std::map<std::string, ConfigDescription> locales_;
std::map<uint16_t, ConfigDescription> densities_;
std::vector<Element*> parent_stack_;
int32_t target_sdk_ = 0;
+
+ std::unique_ptr<ManifestExtractor::Element> root_element_;
+ std::vector<std::unique_ptr<ManifestExtractor::Element>> implied_permissions_;
+ std::vector<FeatureGroup*> feature_groups_;
+ Components components_;
+ Architectures architectures_;
+ const SupportsScreen* supports_screen_;
};
template<typename T> T* ElementCast(ManifestExtractor::Element* element);
@@ -427,6 +540,7 @@ static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
class Manifest : public ManifestExtractor::Element {
public:
Manifest() = default;
+ bool only_package_name;
std::string package;
int32_t versionCode;
std::string versionName;
@@ -462,7 +576,54 @@ class Manifest : public ManifestExtractor::Element {
installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
}
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_package = out_badging->mutable_package();
+ out_package->set_package(package);
+ out_package->set_version_code(versionCode);
+ out_package->set_version_name(versionName);
+ if (compilesdkVersion) {
+ out_package->set_compile_sdk_version(*compilesdkVersion);
+ }
+ if (compilesdkVersionCodename) {
+ out_package->set_compile_sdk_version_codename(*compilesdkVersionCodename);
+ }
+ if (platformVersionName) {
+ out_package->set_platform_version_name(*platformVersionName);
+ } else if (platformVersionNameInt) {
+ out_package->set_platform_version_name(std::to_string(*platformVersionNameInt));
+ }
+ if (platformVersionCode) {
+ out_package->set_platform_version_code(*platformVersionCode);
+ } else if (platformVersionCodeInt) {
+ out_package->set_platform_version_code(std::to_string(*platformVersionCodeInt));
+ }
+
+ if (installLocation) {
+ switch (*installLocation) {
+ case 0:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_AUTO);
+ break;
+ case 1:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_INTERNAL_ONLY);
+ break;
+ case 2:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_PREFER_EXTERNAL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
void Print(text::Printer* printer) override {
+ if (only_package_name) {
+ printer->Println(StringPrintf("package: %s", package.data()));
+ } else {
+ PrintFull(printer);
+ }
+ }
+
+ void PrintFull(text::Printer* printer) {
printer->Print(StringPrintf("package: name='%s' ", package.data()));
printer->Print(StringPrintf("versionCode='%s' ",
(versionCode > 0) ? std::to_string(versionCode).data() : ""));
@@ -598,6 +759,27 @@ class Application : public ManifestExtractor::Element {
printer->Print("application-debuggable\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto application = out_badging->mutable_application();
+ application->set_label(android::ResTable::normalizeForOutput(label.data()));
+ application->set_icon(icon);
+ application->set_banner(banner);
+ application->set_test_only(test_only != 0);
+ application->set_game(is_game != 0);
+ application->set_debuggable(debuggable != 0);
+
+ auto out_locale_labels = application->mutable_locale_labels();
+ for (auto& p : locale_labels) {
+ if (!p.first.empty()) {
+ (*out_locale_labels)[p.first] = p.second;
+ }
+ }
+ auto out_density_icons = application->mutable_density_icons();
+ for (auto& p : density_icons) {
+ (*out_density_icons)[p.first] = p.second;
+ }
+ }
};
/** Represents <uses-sdk> elements. **/
@@ -647,6 +829,23 @@ class UsesSdkBadging : public ManifestExtractor::Element {
printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_sdks = out_badging->mutable_uses_sdk();
+ if (min_sdk) {
+ out_sdks->set_min_sdk_version(*min_sdk);
+ } else if (min_sdk_name) {
+ out_sdks->set_min_sdk_version_name(*min_sdk_name);
+ }
+ if (max_sdk) {
+ out_sdks->set_max_sdk_version(*max_sdk);
+ }
+ if (target_sdk) {
+ out_sdks->set_target_sdk_version(*target_sdk);
+ } else if (target_sdk_name) {
+ out_sdks->set_target_sdk_version_name(*target_sdk_name);
+ }
+ }
};
/** Represents <uses-configuration> elements. **/
@@ -691,6 +890,15 @@ class UsesConfiguarion : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_configuration = out_badging->mutable_uses_configuration();
+ out_configuration->set_req_touch_screen(req_touch_screen);
+ out_configuration->set_req_keyboard_type(req_keyboard_type);
+ out_configuration->set_req_hard_keyboard(req_hard_keyboard);
+ out_configuration->set_req_navigation(req_navigation);
+ out_configuration->set_req_five_way_nav(req_five_way_nav);
+ }
};
/** Represents <supports-screen> elements. **/
@@ -733,54 +941,24 @@ class SupportsScreen : public ManifestExtractor::Element {
}
}
- void PrintScreens(text::Printer* printer, int32_t target_sdk) {
- int32_t small_screen_temp = small_screen;
- int32_t normal_screen_temp = normal_screen;
- int32_t large_screen_temp = large_screen;
- int32_t xlarge_screen_temp = xlarge_screen;
- int32_t any_density_temp = any_density;
-
- // Determine default values for any unspecified screen sizes,
- // based on the target SDK of the package. As of 4 (donut)
- // the screen size support was introduced, so all default to
- // enabled.
- if (small_screen_temp > 0) {
- small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
- }
- if (normal_screen_temp > 0) {
- normal_screen_temp = -1;
- }
- if (large_screen_temp > 0) {
- large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
- }
- if (xlarge_screen_temp > 0) {
- // Introduced in Gingerbread.
- xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
- }
- if (any_density_temp > 0) {
- any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
- compatible_width_limit_dp > 0)
- ? -1
- : 0;
- }
-
+ void PrintScreens(text::Printer* printer, int32_t target_sdk) const {
// Print the formatted screen info
printer->Print("supports-screens:");
- if (small_screen_temp != 0) {
+ if (IsSmallScreenSupported(target_sdk)) {
printer->Print(" 'small'");
}
- if (normal_screen_temp != 0) {
+ if (normal_screen != 0) {
printer->Print(" 'normal'");
}
- if (large_screen_temp != 0) {
+ if (IsLargeScreenSupported(target_sdk)) {
printer->Print(" 'large'");
}
- if (xlarge_screen_temp != 0) {
+ if (IsXLargeScreenSupported(target_sdk)) {
printer->Print(" 'xlarge'");
}
printer->Print("\n");
printer->Print(StringPrintf("supports-any-density: '%s'\n",
- (any_density_temp ) ? "true" : "false"));
+ (IsAnyDensitySupported(target_sdk)) ? "true" : "false"));
if (requires_smallest_width_dp > 0) {
printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
}
@@ -791,6 +969,60 @@ class SupportsScreen : public ManifestExtractor::Element {
printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
}
}
+
+ void ToProtoScreens(pb::Badging* out_badging, int32_t target_sdk) const {
+ auto supports_screen = out_badging->mutable_supports_screen();
+ if (IsSmallScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_SMALL);
+ }
+ if (normal_screen != 0) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_NORMAL);
+ }
+ if (IsLargeScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_LARGE);
+ }
+ if (IsXLargeScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_XLARGE);
+ }
+ supports_screen->set_supports_any_densities(IsAnyDensitySupported(target_sdk));
+ supports_screen->set_requires_smallest_width_dp(requires_smallest_width_dp);
+ supports_screen->set_compatible_width_limit_dp(compatible_width_limit_dp);
+ supports_screen->set_largest_width_limit_dp(largest_width_limit_dp);
+ }
+
+ private:
+ // Determine default values for any unspecified screen sizes,
+ // based on the target SDK of the package. As of 4 (donut)
+ // the screen size support was introduced, so all default to
+ // enabled.
+ bool IsSmallScreenSupported(int32_t target_sdk) const {
+ if (small_screen > 0) {
+ return target_sdk >= SDK_DONUT;
+ }
+ return small_screen != 0;
+ }
+
+ bool IsLargeScreenSupported(int32_t target_sdk) const {
+ if (large_screen > 0) {
+ return target_sdk >= SDK_DONUT;
+ }
+ return large_screen != 0;
+ }
+
+ bool IsXLargeScreenSupported(int32_t target_sdk) const {
+ if (xlarge_screen > 0) {
+ return target_sdk >= SDK_GINGERBREAD;
+ }
+ return xlarge_screen != 0;
+ }
+
+ bool IsAnyDensitySupported(int32_t target_sdk) const {
+ if (any_density > 0) {
+ return target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
+ compatible_width_limit_dp > 0;
+ }
+ return any_density != 0;
+ }
};
/** Represents <feature-group> elements. **/
@@ -821,6 +1053,18 @@ class FeatureGroup : public ManifestExtractor::Element {
}
}
+ virtual void GroupToProto(pb::Badging* out_badging) {
+ auto feature_group = out_badging->add_feature_groups();
+ feature_group->set_label(label);
+ feature_group->set_open_gles_version(open_gles_version);
+ for (auto& feature : features_) {
+ auto out_feature = feature_group->add_features();
+ out_feature->set_name(feature.first);
+ out_feature->set_required(feature.second.required);
+ out_feature->set_version(feature.second.version);
+ }
+ }
+
/** Adds a feature to the feature group. */
void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
features_.insert(std::make_pair(name, Feature{ required, version }));
@@ -910,6 +1154,23 @@ class CommonFeatureGroup : public FeatureGroup {
}
}
+ virtual void GroupToProto(pb::Badging* out_badging) override {
+ FeatureGroup::GroupToProto(out_badging);
+ auto feature_group =
+ out_badging->mutable_feature_groups(out_badging->feature_groups_size() - 1);
+ for (auto& feature : implied_features_) {
+ if (features_.find(feature.first) == features_.end()) {
+ auto out_feature = feature_group->add_features();
+ out_feature->set_name(feature.first);
+ auto implied_data = out_feature->mutable_implied_data();
+ implied_data->set_from_sdk_23_permission(feature.second.implied_from_sdk_k23);
+ for (auto& reason : feature.second.reasons) {
+ implied_data->add_reasons(reason);
+ }
+ }
+ }
+ }
+
/** Returns true if the feature group has the given feature. */
bool HasFeature(const std::string& name) override {
return FeatureGroup::HasFeature(name)
@@ -1050,7 +1311,7 @@ class UsesFeature : public ManifestExtractor::Element {
// common feature group
FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
if (!feature_group) {
- feature_group = extractor()->GetCommonFeatureGroup();
+ feature_group = extractor()->common_feature_group();
} else {
// All features in side of <feature-group> elements are required.
required = true;
@@ -1068,12 +1329,14 @@ class UsesFeature : public ManifestExtractor::Element {
class UsesPermission : public ManifestExtractor::Element {
public:
UsesPermission() = default;
+ bool implied;
std::string name;
std::vector<std::string> requiredFeatures;
std::vector<std::string> requiredNotFeatures;
int32_t required = true;
int32_t maxSdkVersion = -1;
int32_t usesPermissionFlags = 0;
+ std::string impliedReason;
void Extract(xml::Element* element) override {
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
@@ -1094,7 +1357,7 @@ class UsesPermission : public ManifestExtractor::Element {
FindAttribute(element, USES_PERMISSION_FLAGS_ATTR), 0);
if (!name.empty()) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
}
}
@@ -1126,17 +1389,37 @@ class UsesPermission : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+ if (implied) {
+ printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ if ((usesPermissionFlags & kNeverForLocation) != 0) {
+ printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
+ }
+ printer->Print(StringPrintf(" reason='%s'\n", impliedReason.data()));
+ }
}
- void PrintImplied(text::Printer* printer, const std::string& reason) {
- printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
- if (maxSdkVersion >= 0) {
- printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
- }
- if ((usesPermissionFlags & kNeverForLocation) != 0) {
- printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto permission = out_badging->add_uses_permissions();
+ permission->set_name(name);
+ if (maxSdkVersion > 0) {
+ permission->set_max_sdk_version(maxSdkVersion);
+ }
+ if ((usesPermissionFlags & kNeverForLocation) != 0) {
+ permission->mutable_permission_flags()->set_never_for_location(true);
+ }
+ for (auto& requiredFeature : requiredFeatures) {
+ permission->add_required_features(requiredFeature);
+ }
+ for (auto& requiredNotFeature : requiredNotFeatures) {
+ permission->add_required_not_features(requiredNotFeature);
+ }
+ permission->set_required(required != 0);
+ permission->set_implied(implied);
}
- printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
}
};
@@ -1184,7 +1467,7 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
if (name) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
}
}
@@ -1198,6 +1481,17 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ auto permission = out_badging->add_uses_permissions();
+ permission->set_sdk23_and_above(true);
+ permission->set_name(*name);
+ if (maxSdkVersion) {
+ permission->set_max_sdk_version(*maxSdkVersion);
+ }
+ }
+ }
};
/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
@@ -1215,6 +1509,12 @@ class Permission : public ManifestExtractor::Element {
printer->Print(StringPrintf("permission: %s\n", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ out_badging->add_permissions()->set_name(name);
+ }
+ }
};
/** Represents <activity> elements. **/
@@ -1256,7 +1556,7 @@ class Activity : public ManifestExtractor::Element {
auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
if (orientation) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
int orien = *orientation;
if (orien == 0 || orien == 6 || orien == 8) {
// Requests landscape, sensorLandscape, or reverseLandscape.
@@ -1295,6 +1595,22 @@ class Activity : public ManifestExtractor::Element {
icon.data(), banner.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (has_main_action && has_launcher_category) {
+ auto activity = out_badging->mutable_launchable_activity();
+ activity->set_name(name);
+ activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+ activity->set_icon(icon);
+ }
+ if (has_leanback_launcher_category) {
+ auto activity = out_badging->mutable_leanback_launchable_activity();
+ activity->set_name(name);
+ activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+ activity->set_icon(icon);
+ activity->set_banner(banner);
+ }
+ }
};
/** Represents <intent-filter> elements. */
@@ -1395,6 +1711,14 @@ class UsesLibrary : public ManifestExtractor::Element {
(required == 0) ? "-not-required" : "", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto uses_library = out_badging->add_uses_libraries();
+ uses_library->set_name(name);
+ uses_library->set_required(required != 0);
+ }
+ }
};
/** Represents <static-library> elements. **/
@@ -1419,6 +1743,13 @@ class StaticLibrary : public ManifestExtractor::Element {
"static-library: name='%s' version='%d' versionMajor='%d'\n",
name.data(), version, versionMajor));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto static_library = out_badging->mutable_static_library();
+ static_library->set_name(name);
+ static_library->set_version(version);
+ static_library->set_version_major(versionMajor);
+ }
};
/** Represents <uses-static-library> elements. **/
@@ -1459,6 +1790,16 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto uses_static_library = out_badging->add_uses_static_libraries();
+ uses_static_library->set_name(name);
+ uses_static_library->set_version(version);
+ uses_static_library->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_static_library->add_certificates(cert);
+ }
+ }
};
/** Represents <sdk-library> elements. **/
@@ -1480,6 +1821,12 @@ class SdkLibrary : public ManifestExtractor::Element {
printer->Print(
StringPrintf("sdk-library: name='%s' versionMajor='%d'\n", name.data(), versionMajor));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto sdk_library = out_badging->mutable_sdk_library();
+ sdk_library->set_name(name);
+ sdk_library->set_version_major(versionMajor);
+ }
};
/** Represents <uses-sdk-library> elements. **/
@@ -1517,6 +1864,15 @@ class UsesSdkLibrary : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto uses_sdk_library = out_badging->add_uses_sdk_libraries();
+ uses_sdk_library->set_name(name);
+ uses_sdk_library->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_sdk_library->add_certificates(cert);
+ }
+ }
};
/** Represents <uses-native-library> elements. **/
@@ -1540,6 +1896,14 @@ class UsesNativeLibrary : public ManifestExtractor::Element {
(required == 0) ? "-not-required" : "", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto uses_native_library = out_badging->add_uses_native_libraries();
+ uses_native_library->set_name(name);
+ uses_native_library->set_required(required != 0);
+ }
+ }
};
/**
@@ -1565,21 +1929,39 @@ class MetaData : public ManifestExtractor::Element {
void Print(text::Printer* printer) override {
if (extractor()->options_.include_meta_data && !name.empty()) {
- printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
+ printer->Print(StringPrintf("meta-data: name='%s'", name.data()));
if (!value.empty()) {
- printer->Print(StringPrintf("value='%s' ", value.data()));
+ printer->Print(StringPrintf(" value='%s'", value.data()));
} else if (value_int) {
- printer->Print(StringPrintf("value='%d' ", *value_int));
+ printer->Print(StringPrintf(" value='%d'", *value_int));
} else {
if (!resource.empty()) {
- printer->Print(StringPrintf("resource='%s' ", resource.data()));
+ printer->Print(StringPrintf(" resource='%s'", resource.data()));
} else if (resource_int) {
- printer->Print(StringPrintf("resource='%d' ", *resource_int));
+ printer->Print(StringPrintf(" resource='%d'", *resource_int));
}
}
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto metadata = out_badging->add_metadata();
+ metadata->set_name(name);
+ if (!value.empty()) {
+ metadata->set_value_string(value);
+ } else if (value_int) {
+ metadata->set_value_int(*value_int);
+ } else {
+ if (!resource.empty()) {
+ metadata->set_resource_string(resource);
+ } else if (resource_int) {
+ metadata->set_resource_int(*resource_int);
+ }
+ }
+ }
+ }
};
/**
@@ -1709,6 +2091,13 @@ class SupportsInput : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto supports_input = out_badging->mutable_supports_input();
+ for (auto& input : inputs) {
+ supports_input->add_inputs(input);
+ }
+ }
};
/** Represents <input-type> elements. **/
@@ -1742,6 +2131,12 @@ class OriginalPackage : public ManifestExtractor::Element {
printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ out_badging->mutable_package()->set_original_package(*name);
+ }
+ }
};
@@ -1780,6 +2175,21 @@ class Overlay : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto overlay = out_badging->mutable_overlay();
+ if (target_package) {
+ overlay->set_target_package(*target_package);
+ }
+ overlay->set_priority(priority);
+ overlay->set_static_(is_static);
+ if (required_property_name) {
+ overlay->set_required_property_name(*required_property_name);
+ }
+ if (required_property_value) {
+ overlay->set_required_property_value(*required_property_value);
+ }
+ }
};
/** * Represents <package-verifier> elements. **/
@@ -1800,6 +2210,14 @@ class PackageVerifier : public ManifestExtractor::Element {
name->data(), public_key->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto package_verifier = out_badging->mutable_package_verifier();
+ if (name && public_key) {
+ package_verifier->set_name(*name);
+ package_verifier->set_public_key(*public_key);
+ }
+ }
};
/** Represents <uses-package> elements. **/
@@ -1848,6 +2266,21 @@ class UsesPackage : public ManifestExtractor::Element {
}
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ auto uses_package = out_badging->add_uses_packages();
+ uses_package->set_name(*name);
+ if (packageType) {
+ uses_package->set_package_type(*packageType);
+ uses_package->set_version(version);
+ uses_package->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_package->add_certificates(cert);
+ }
+ }
+ }
+ }
};
/** Represents <additional-certificate> elements. **/
@@ -1880,6 +2313,14 @@ class Screen : public ManifestExtractor::Element {
size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (size && density) {
+ auto screen = out_badging->mutable_compatible_screens()->add_screens();
+ screen->set_density(*density);
+ screen->set_size(*size);
+ }
+ }
};
/**
@@ -1925,6 +2366,12 @@ class SupportsGlTexture : public ManifestExtractor::Element {
printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ out_badging->mutable_supports_gl_texture()->add_name(*name);
+ }
+ }
};
/** Represents <property> elements. **/
@@ -1960,6 +2407,24 @@ class Property : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto property = out_badging->add_properties();
+ property->set_name(name);
+ if (!value.empty()) {
+ property->set_value_string(value);
+ } else if (value_int) {
+ property->set_value_int(*value_int);
+ } else {
+ if (!resource.empty()) {
+ property->set_resource_string(resource);
+ } else if (resource_int) {
+ property->set_resource_int(*resource_int);
+ }
+ }
+ }
+ }
};
/** Recursively prints the extracted badging element. */
@@ -1970,27 +2435,36 @@ static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
}
}
-bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
+/** Recursively serializes extracted badging elements to proto. */
+static void ToProto(ManifestExtractor::Element* el, pb::Badging* out_badging) {
+ el->ToProto(out_badging);
+ for (auto& child : el->children()) {
+ ToProto(child.get(), out_badging);
+ }
+}
+
+bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
// Load the manifest
- std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
- if (doc == nullptr) {
- diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
+ doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
+ if (doc_ == nullptr) {
+ diag->Error(android::DiagMessage() << "failed to find AndroidManifest.xml");
return false;
}
- xml::Element* element = doc->root.get();
+ xml::Element* element = doc_->root.get();
if (element->name != "manifest") {
- diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
+ diag->Error(android::DiagMessage() << "manifest does not start with <manifest> tag");
return false;
}
// Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
// printing only permission elements is requested
if (options_.only_permissions) {
- std::unique_ptr<ManifestExtractor::Element> manifest_element =
- ManifestExtractor::Element::Inflate(this, element);
+ root_element_ = ManifestExtractor::Element::Inflate(this, element);
+
+ if (auto manifest = ElementCast<Manifest>(root_element_.get())) {
+ manifest->only_package_name = true;
- if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
for (xml::Element* child : element->GetChildElements()) {
if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
|| child->name == "permission") {
@@ -1999,15 +2473,8 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
manifest->AddChild(permission_element);
}
}
-
- printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
- ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
- el->Print(printer);
- });
-
return true;
}
-
return false;
}
@@ -2041,27 +2508,24 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
}
// Extract badging information
- auto root = Visit(element);
+ root_element_ = Visit(element);
// Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
// attribute values from the last defined tag.
std::vector<UsesSdkBadging*> filtered_uses_sdk_tags;
- for (const auto& child : root->children()) {
+ for (const auto& child : root_element_->children()) {
if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) {
filtered_uses_sdk_tags.emplace_back(uses_sdk);
}
}
if (filtered_uses_sdk_tags.size() >= 2U) {
filtered_uses_sdk_tags.pop_back();
- root->Filter([&](const ManifestExtractor::Element* e) {
+ root_element_->Filter([&](const ManifestExtractor::Element* e) {
return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) !=
filtered_uses_sdk_tags.end();
});
}
- // Print the elements in order seen
- Print(root.get(), printer);
-
/** Recursively checks the extracted elements for the specified permission. **/
auto FindPermission = [&](ManifestExtractor::Element* root,
const std::string& name) -> ManifestExtractor::Element* {
@@ -2073,30 +2537,30 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
});
};
- auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
- int32_t max_sdk_version) -> void {
+ auto AddImpliedPermission = [&](const std::string& name, const std::string& reason,
+ int32_t max_sdk_version) -> void {
auto permission = util::make_unique<UsesPermission>();
permission->name = name;
permission->maxSdkVersion = max_sdk_version;
- permission->Print(printer);
- permission->PrintImplied(printer, reason);
+ permission->implied = true;
+ permission->impliedReason = reason;
+ implied_permissions_.push_back(std::move(permission));
};
// Implied permissions
// Pre-1.6 implicitly granted permission compatibility logic
- CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
bool insert_write_external = false;
auto write_external_permission = ElementCast<UsesPermission>(
- FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
+ FindPermission(root_element_.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
if (target_sdk() < SDK_DONUT) {
if (!write_external_permission) {
- PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
+ AddImpliedPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
insert_write_external = true;
}
- if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
- PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_PHONE_STATE")) {
+ AddImpliedPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
}
}
@@ -2104,62 +2568,60 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
// force them to always take READ_EXTERNAL_STORAGE as well. We always
// do this (regardless of target API version) because we can't have
// an app with write permission but not read permission.
- auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
+ auto read_external =
+ FindPermission(root_element_.get(), "android.permission.READ_EXTERNAL_STORAGE");
if (!read_external && (insert_write_external || write_external_permission)) {
- PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
- "requested WRITE_EXTERNAL_STORAGE",
- (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
+ AddImpliedPermission(
+ "android.permission.READ_EXTERNAL_STORAGE", "requested WRITE_EXTERNAL_STORAGE",
+ (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
}
// Pre-JellyBean call log permission compatibility.
if (target_sdk() < SDK_JELLY_BEAN) {
- if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
- && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
- PrintPermission("android.permission.READ_CALL_LOG",
- "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.READ_CONTACTS")) {
+ AddImpliedPermission("android.permission.READ_CALL_LOG",
+ "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
}
- if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
- && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
- PrintPermission("android.permission.WRITE_CALL_LOG",
- "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.WRITE_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.WRITE_CONTACTS")) {
+ AddImpliedPermission("android.permission.WRITE_CALL_LOG",
+ "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
}
}
// If the app hasn't declared the touchscreen as a feature requirement (either
// directly or implied, required or not), then the faketouch feature is implied.
- if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
- common_feature_group->addImpliedFeature("android.hardware.faketouch",
- "default feature for all apps", false);
+ if (!common_feature_group()->HasFeature("android.hardware.touchscreen")) {
+ common_feature_group()->addImpliedFeature("android.hardware.faketouch",
+ "default feature for all apps", false);
}
// Only print the common feature group if no feature group is defined
std::vector<FeatureGroup*> feature_groups;
- ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
if (auto feature_group = ElementCast<FeatureGroup>(el)) {
feature_groups.push_back(feature_group);
}
});
if (feature_groups.empty()) {
- common_feature_group->PrintGroup(printer);
+ feature_groups_.push_back(common_feature_group());
} else {
// Merge the common feature group into the feature group
for (auto& feature_group : feature_groups) {
- feature_group->open_gles_version = std::max(feature_group->open_gles_version,
- common_feature_group->open_gles_version);
- feature_group->Merge(common_feature_group);
- feature_group->PrintGroup(printer);
+ feature_group->Merge(common_feature_group());
+ feature_groups_.push_back(feature_group);
}
};
// Collect the component types of the application
- std::set<std::string> components;
- ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&](ManifestExtractor::Element* el) -> void {
if (ElementCast<Action>(el)) {
auto action = ElementCast<Action>(el);
if (!action->component.empty()) {
- components.insert(action->component);
+ components_.discovered_components.insert(action->component);
return;
}
}
@@ -2167,15 +2629,14 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
if (ElementCast<Category>(el)) {
auto category = ElementCast<Category>(el);
if (!category->component.empty()) {
- components.insert(category->component);
+ components_.discovered_components.insert(category->component);
return;
}
}
});
// Check for the payment component
- auto apk = apk_;
- ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [this, &diag](ManifestExtractor::Element* el) -> void {
if (auto service = ElementCast<Service>(el)) {
auto host_apdu_action = ElementCast<Action>(FindElement(service,
[&](ManifestExtractor::Element* el) -> bool {
@@ -2193,140 +2654,87 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
return false;
}));
- ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
- &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
- if (auto meta_data = ElementCast<MetaData>(el)) {
- if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
- || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
- && offhost_apdu_action)) {
-
- // Attempt to load the resource file
- if (!meta_data->resource.empty()) {
- return;
- }
- auto resource = apk->LoadXml(meta_data->resource, diag);
- if (!resource) {
- return;
- }
-
- // Look for the payment category on an <aid-group> element
- auto& root = resource.get()->root;
- if ((host_apdu_action && root->name == "host-apdu-service")
- || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
-
- for (auto& child : root->GetChildElements()) {
- if (child->name == "aid-group") {
- auto category = FindAttribute(child, CATEGORY_ATTR);
- if (category && category->value == "payment") {
- components.insert("payment");
- return;
- }
- }
- }
- }
- }
- }
- });
+ ForEachChild(service,
+ [this, &diag, &host_apdu_action,
+ &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
+ if (auto meta_data = ElementCast<MetaData>(el)) {
+ if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" &&
+ host_apdu_action) ||
+ (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service" &&
+ offhost_apdu_action)) {
+ // Attempt to load the resource file
+ if (!meta_data->resource.empty()) {
+ return;
+ }
+ auto resource = this->apk_->LoadXml(meta_data->resource, diag);
+ if (!resource) {
+ return;
+ }
+
+ // Look for the payment category on an <aid-group> element
+ auto& root = resource.get()->root;
+ if ((host_apdu_action && root->name == "host-apdu-service") ||
+ (offhost_apdu_action && root->name == "offhost-apdu-service")) {
+ for (auto& child : root->GetChildElements()) {
+ if (child->name == "aid-group") {
+ auto category = FindAttribute(child, CATEGORY_ATTR);
+ if (category && category->value == "payment") {
+ this->components_.discovered_components.insert("payment");
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
});
- // Print the components types if they are present
- auto PrintComponent = [&components, &printer](const std::string& component) -> void {
- if (components.find(component) != components.end()) {
- printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
- }
- };
-
- PrintComponent("app-widget");
- PrintComponent("device-admin");
- PrintComponent("ime");
- PrintComponent("wallpaper");
- PrintComponent("accessibility");
- PrintComponent("print-service");
- PrintComponent("payment");
- PrintComponent("search");
- PrintComponent("document-provider");
- PrintComponent("launcher");
- PrintComponent("notification-listener");
- PrintComponent("dream");
- PrintComponent("camera");
- PrintComponent("camera-secure");
-
- // Print presence of main activity
- if (components.find("main") != components.end()) {
- printer->Print("main\n");
- }
-
- // Print presence of activities, recivers, and services with no special components
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ // Print presence of activities, receivers, and services with no special components
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto activity = ElementCast<Activity>(el)) {
if (!activity->has_component_) {
- printer->Print("other-activities\n");
+ components_.other_activities = true;
return true;
}
}
return false;
});
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto receiver = ElementCast<Receiver>(el)) {
if (!receiver->has_component) {
- printer->Print("other-receivers\n");
+ components_.other_receivers = true;
return true;
}
}
return false;
});
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto service = ElementCast<Service>(el)) {
if (!service->has_component) {
- printer->Print("other-services\n");
+ components_.other_services = true;
return true;
}
}
return false;
});
- // Print the supported screens
- SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
- [&](ManifestExtractor::Element* el) -> bool {
- return ElementCast<SupportsScreen>(el) != nullptr;
- }));
-
- if (screen) {
- screen->PrintScreens(printer, target_sdk_);
- } else {
- // Print the default supported screens
- SupportsScreen default_screens;
- default_screens.PrintScreens(printer, target_sdk_);
- }
-
- // Print all the unique locales of the apk
- printer->Print("locales:");
- for (auto& config : locales_) {
- if (config.first.empty()) {
- printer->Print(" '--_--'");
- } else {
- printer->Print(StringPrintf(" '%s'", config.first.data()));
- }
- }
- printer->Print("\n");
-
- // Print all the densities locales of the apk
- printer->Print("densities:");
- for (auto& config : densities_) {
- printer->Print(StringPrintf(" '%d'", config.first));
- }
- printer->Print("\n");
+ // Gather the supported screens
+ const static SupportsScreen default_screens{};
+ SupportsScreen* screen = ElementCast<SupportsScreen>(
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ return ElementCast<SupportsScreen>(el) != nullptr;
+ }));
+ supports_screen_ = screen ? screen : &default_screens;
- // Print the supported architectures of the app
- std::set<std::string> architectures;
+ // Gather the supported architectures_ of the app
+ std::set<std::string> architectures_from_apk;
auto it = apk_->GetFileCollection()->Iterator();
while (it->HasNext()) {
auto file_path = it->Next()->GetSource().path;
-
-
size_t pos = file_path.find("lib/");
if (pos != std::string::npos) {
file_path = file_path.substr(pos + 4);
@@ -2335,17 +2743,18 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
file_path = file_path.substr(0, pos);
}
- architectures.insert(file_path);
+ architectures_from_apk.insert(file_path);
}
}
// Determine if the application has multiArch supports
- auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
- if (auto application = ElementCast<Application>(el)) {
- return application->has_multi_arch;
- }
- return false;
- });
+ auto has_multi_arch =
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto application = ElementCast<Application>(el)) {
+ return application->has_multi_arch;
+ }
+ return false;
+ });
bool output_alt_native_code = false;
// A multiArch package is one that contains 64-bit and
@@ -2366,29 +2775,85 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
const std::string kIntel64 = "x86_64";
const std::string kArm64 = "arm64-v8a";
- auto arch = architectures.find(kIntel64);
- if (arch == architectures.end()) {
- arch = architectures.find(kArm64);
+ auto arch = architectures_from_apk.find(kIntel64);
+ if (arch == architectures_from_apk.end()) {
+ arch = architectures_from_apk.find(kArm64);
}
- if (arch != architectures.end()) {
- printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
- architectures.erase(arch);
+ if (arch != architectures_from_apk.end()) {
+ architectures_.architectures.insert(*arch);
+ architectures_from_apk.erase(arch);
output_alt_native_code = true;
}
}
-
- if (architectures.size() > 0) {
+ for (auto& arch : architectures_from_apk) {
if (output_alt_native_code) {
- printer->Print("alt-");
+ architectures_.alt_architectures.insert(arch);
+ } else {
+ architectures_.architectures.insert(arch);
}
- printer->Print("native-code:");
- for (auto& arch : architectures) {
- printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ return true;
+}
+
+bool ManifestExtractor::Dump(text::Printer* printer) {
+ Print(root_element_.get(), printer);
+ if (options_.only_permissions) {
+ return true;
+ }
+
+ for (auto& implied_permission : implied_permissions_) {
+ implied_permission->Print(printer);
+ }
+ for (auto& feature_group : feature_groups_) {
+ feature_group->PrintGroup(printer);
+ }
+ components_.Print(printer);
+ supports_screen_->PrintScreens(printer, target_sdk_);
+
+ // Print all the unique locales of the apk
+ printer->Print("locales:");
+ for (auto& config : locales_) {
+ if (config.first.empty()) {
+ printer->Print(" '--_--'");
+ } else {
+ printer->Print(StringPrintf(" '%s'", config.first.data()));
+ }
+ }
+ printer->Print("\n");
+
+ // Print all the densities locales of the apk
+ printer->Print("densities:");
+ for (auto& config : densities_) {
+ printer->Print(StringPrintf(" '%d'", config.first));
+ }
+ printer->Print("\n");
+
+ architectures_.Print(printer);
+ return true;
+}
+
+bool ManifestExtractor::DumpProto(pb::Badging* out_badging) {
+ ToProto(root_element_.get(), out_badging);
+ for (auto& implied_permission : implied_permissions_) {
+ implied_permission->ToProto(out_badging);
+ }
+ for (auto& feature_group : feature_groups_) {
+ feature_group->GroupToProto(out_badging);
+ }
+ components_.ToProto(out_badging);
+ supports_screen_->ToProtoScreens(out_badging, target_sdk_);
+
+ for (auto& config : locales_) {
+ if (!config.first.empty()) {
+ out_badging->add_locales(config.first);
}
- printer->Print("\n");
+ }
+ for (auto& config : densities_) {
+ out_badging->add_densities(config.first);
}
+ architectures_.ToProto(out_badging);
return true;
}
@@ -2527,11 +2992,23 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Elemen
return element;
}
-
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
ManifestExtractor extractor(apk, options);
- return extractor.Dump(printer, diag) ? 0 : 1;
+ if (!extractor.Extract(diag)) {
+ return 1;
+ }
+ return extractor.Dump(printer) ? 0 : 1;
+}
+
+int DumpBadgingProto(LoadedApk* apk, pb::Badging* out_badging, android::IDiagnostics* diag) {
+ DumpManifestOptions options{/* include_meta_data= */ true,
+ /* only_permissions= */ false};
+ ManifestExtractor extractor(apk, options);
+ if (!extractor.Extract(diag)) {
+ return 1;
+ }
+ return extractor.DumpProto(out_badging) ? 0 : 1;
}
} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
index daf22ed57a84..138b9e377b8a 100644
--- a/tools/aapt2/dump/DumpManifest.h
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -17,8 +17,9 @@
#ifndef AAPT2_DUMP_MANIFEST_H
#define AAPT2_DUMP_MANIFEST_H
-#include "Diagnostics.h"
+#include "ApkInfo.pb.h"
#include "LoadedApk.h"
+#include "androidfw/IDiagnostics.h"
#include "text/Printer.h"
namespace aapt {
@@ -32,8 +33,11 @@ struct DumpManifestOptions {
/** Print information extracted from the manifest of the APK. */
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
+
+/** Extracts badging data from the manifest of the APK and stores it in Badging proto. */
+int DumpBadgingProto(LoadedApk* apk, pb::Badging* out_badging, android::IDiagnostics* diag);
} // namespace aapt
-#endif // AAPT2_DUMP_MANIFEST_H \ No newline at end of file
+#endif // AAPT2_DUMP_MANIFEST_H
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp
index c20b053c37b1..80c16188aca4 100644
--- a/tools/aapt2/format/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -25,9 +25,9 @@
#include "android-base/macros.h"
#include "android-base/utf8.h"
#include "androidfw/StringPiece.h"
-#include "ziparchive/zip_writer.h"
-
#include "util/Files.h"
+#include "util/Util.h"
+#include "ziparchive/zip_writer.h"
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
@@ -256,21 +256,21 @@ class ZipFileWriter : public IArchiveWriter {
} // namespace
-std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(IDiagnostics* diag,
+std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
const StringPiece& path) {
std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>();
if (!writer->Open(path)) {
- diag->Error(DiagMessage(path) << writer->GetError());
+ diag->Error(android::DiagMessage(path) << writer->GetError());
return {};
}
return std::move(writer);
}
-std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(IDiagnostics* diag,
+std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
const StringPiece& path) {
std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>();
if (!writer->Open(path)) {
- diag->Error(DiagMessage(path) << writer->GetError());
+ diag->Error(android::DiagMessage(path) << writer->GetError());
return {};
}
return std::move(writer);
diff --git a/tools/aapt2/format/Archive.h b/tools/aapt2/format/Archive.h
index 4e8a39df9165..55b0b2f0f017 100644
--- a/tools/aapt2/format/Archive.h
+++ b/tools/aapt2/format/Archive.h
@@ -22,12 +22,11 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-#include "Diagnostics.h"
#include "io/Io.h"
-#include "util/BigBuffer.h"
#include "util/Files.h"
namespace aapt {
@@ -70,10 +69,10 @@ class IArchiveWriter : public ::google::protobuf::io::CopyingOutputStream {
virtual std::string GetError() const = 0;
};
-std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(IDiagnostics* diag,
+std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
const android::StringPiece& path);
-std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(IDiagnostics* diag,
+std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
const android::StringPiece& path);
} // namespace aapt
diff --git a/tools/aapt2/format/Container.h b/tools/aapt2/format/Container.h
index aa5c82cd322c..121c592537bf 100644
--- a/tools/aapt2/format/Container.h
+++ b/tools/aapt2/format/Container.h
@@ -19,14 +19,13 @@
#include <inttypes.h>
-#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream.h"
-
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
+#include "androidfw/BigBuffer.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream.h"
#include "io/Io.h"
#include "io/Util.h"
-#include "util/BigBuffer.h"
namespace aapt {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c65c55024bab..d9e379db84b7 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -18,19 +18,19 @@
#include <algorithm>
#include <map>
+#include <optional>
#include <string>
+#include "ResourceTable.h"
+#include "ResourceUtils.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/Source.h"
#include "androidfw/TypeWrappers.h"
-
-#include "ResourceTable.h"
-#include "ResourceUtils.h"
-#include "ResourceValues.h"
-#include "Source.h"
-#include "ValueVisitor.h"
#include "format/binary/ResChunkPullParser.h"
#include "util/Util.h"
@@ -50,7 +50,7 @@ static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
std::u16string dst;
dst.resize(utf16_len);
for (size_t i = 0; i < utf16_len; i++) {
- dst[i] = util::DeviceToHost16(src[i]);
+ dst[i] = android::util::DeviceToHost16(src[i]);
}
return dst;
}
@@ -87,8 +87,8 @@ class ReferenceIdToNameVisitor : public DescendingValueVisitor {
} // namespace
BinaryResourceParser::BinaryResourceParser(IDiagnostics* diag, ResourceTable* table,
- const Source& source, const void* data, size_t len,
- io::IFileCollection* files)
+ const android::Source& source, const void* data,
+ size_t len, io::IFileCollection* files)
: diag_(diag), table_(table), source_(source), data_(data), data_len_(len), files_(files) {
}
@@ -96,13 +96,13 @@ bool BinaryResourceParser::Parse() {
ResChunkPullParser parser(data_, data_len_);
if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
- diag_->Error(DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
return false;
}
if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- diag_->Error(DiagMessage(source_) << StringPrintf("unknown chunk of type 0x%02x",
- static_cast<int>(parser.chunk()->type)));
+ diag_->Error(android::DiagMessage(source_) << StringPrintf(
+ "unknown chunk of type 0x%02x", static_cast<int>(parser.chunk()->type)));
return false;
}
@@ -112,18 +112,18 @@ bool BinaryResourceParser::Parse() {
if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
} else {
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< StringPrintf("unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
static_cast<int>(parser.chunk()->type)));
}
}
if (!staged_entries_to_remove_.empty()) {
- diag_->Error(DiagMessage(source_) << "didn't find " << staged_entries_to_remove_.size()
- << " original staged resources");
+ diag_->Error(android::DiagMessage(source_) << "didn't find " << staged_entries_to_remove_.size()
+ << " original staged resources");
return false;
}
@@ -134,20 +134,20 @@ bool BinaryResourceParser::Parse() {
bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
if (!table_header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_header chunk");
return false;
}
ResChunkPullParser parser(GetChunkData(&table_header->header),
GetChunkDataLen(&table_header->header));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
+ switch (android::util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (value_pool_.getError() == NO_INIT) {
- status_t err =
- value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ status_t err = value_pool_.setTo(parser.chunk(),
+ android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "corrupt string pool in ResTable: " << value_pool_.getError());
return false;
}
@@ -155,7 +155,7 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
// Reserve some space for the strings we are going to add.
table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
} else {
- diag_->Warn(DiagMessage(source_) << "unexpected string pool in ResTable");
+ diag_->Warn(android::DiagMessage(source_) << "unexpected string pool in ResTable");
}
break;
@@ -166,15 +166,15 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
break;
default:
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ << static_cast<int>(android::util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
return true;
@@ -185,13 +185,13 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
if (!package_header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_package chunk");
return false;
}
- uint32_t package_id = util::DeviceToHost32(package_header->id);
+ uint32_t package_id = android::util::DeviceToHost32(package_header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
- diag_->Error(DiagMessage(source_) << "package ID is too big (" << package_id << ")");
+ diag_->Error(android::DiagMessage(source_) << "package ID is too big (" << package_id << ")");
return false;
}
@@ -199,9 +199,10 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
arraysize(package_header->name));
- ResourceTablePackage* package = table_->FindOrCreatePackage(util::Utf16ToUtf8(package_name));
+ ResourceTablePackage* package =
+ table_->FindOrCreatePackage(android::util::Utf16ToUtf8(package_name));
if (!package) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "incompatible package '" << package_name << "' with ID " << package_id);
return false;
}
@@ -214,26 +215,28 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
ResChunkPullParser parser(GetChunkData(&package_header->header),
GetChunkDataLen(&package_header->header));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
+ switch (android::util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (type_pool_.getError() == NO_INIT) {
status_t err =
- type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ type_pool_.setTo(parser.chunk(), android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "corrupt type string pool in "
- << "ResTable_package: " << type_pool_.getError());
+ diag_->Error(android::DiagMessage(source_)
+ << "corrupt type string pool in "
+ << "ResTable_package: " << type_pool_.getError());
return false;
}
} else if (key_pool_.getError() == NO_INIT) {
status_t err =
- key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ key_pool_.setTo(parser.chunk(), android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "corrupt key string pool in "
- << "ResTable_package: " << key_pool_.getError());
+ diag_->Error(android::DiagMessage(source_)
+ << "corrupt key string pool in "
+ << "ResTable_package: " << key_pool_.getError());
return false;
}
} else {
- diag_->Warn(DiagMessage(source_) << "unexpected string pool");
+ diag_->Warn(android::DiagMessage(source_) << "unexpected string pool");
}
break;
@@ -268,15 +271,15 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
break;
default:
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ << static_cast<int>(android::util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
return false;
}
@@ -290,18 +293,19 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
const ResChunk_header* chunk, uint8_t package_id) {
if (type_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing type string pool");
return false;
}
const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
if (!type_spec) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
return false;
}
if (type_spec->id == 0) {
- diag_->Error(DiagMessage(source_) << "ResTable_typeSpec has invalid id: " << type_spec->id);
+ diag_->Error(android::DiagMessage(source_)
+ << "ResTable_typeSpec has invalid id: " << type_spec->id);
return false;
}
@@ -312,25 +316,26 @@ bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
// There can only be 2^16 entries in a type, because that is the ID
// space for entries (EEEE) in the resource ID 0xPPTTEEEE.
if (entry_count > std::numeric_limits<uint16_t>::max()) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "ResTable_typeSpec has too many entries (" << entry_count << ")");
return false;
}
- const size_t data_size = util::DeviceToHost32(type_spec->header.size) -
- util::DeviceToHost16(type_spec->header.headerSize);
+ const size_t data_size = android::util::DeviceToHost32(type_spec->header.size) -
+ android::util::DeviceToHost16(type_spec->header.headerSize);
if (entry_count * sizeof(uint32_t) > data_size) {
- diag_->Error(DiagMessage(source_) << "ResTable_typeSpec too small to hold entries.");
+ diag_->Error(android::DiagMessage(source_) << "ResTable_typeSpec too small to hold entries.");
return false;
}
// Record the type_spec_flags for later. We don't know resource names yet, and we need those
// to mark resources as overlayable.
const uint32_t* type_spec_flags = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<uintptr_t>(type_spec) + util::DeviceToHost16(type_spec->header.headerSize));
+ reinterpret_cast<uintptr_t>(type_spec) +
+ android::util::DeviceToHost16(type_spec->header.headerSize));
for (size_t i = 0; i < entry_count; i++) {
ResourceId id(package_id, type_spec->id, static_cast<size_t>(i));
- entry_type_spec_flags_[id] = util::DeviceToHost32(type_spec_flags[i]);
+ entry_type_spec_flags_[id] = android::util::DeviceToHost32(type_spec_flags[i]);
}
return true;
}
@@ -338,12 +343,12 @@ bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResChunk_header* chunk, uint8_t package_id) {
if (type_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing type string pool");
return false;
}
if (key_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing key string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing key string pool");
return false;
}
@@ -351,22 +356,23 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
// a lot and has its own code to handle variable size.
const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
if (!type) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_type chunk");
return false;
}
if (type->id == 0) {
- diag_->Error(DiagMessage(source_) << "ResTable_type has invalid id: " << (int)type->id);
+ diag_->Error(android::DiagMessage(source_)
+ << "ResTable_type has invalid id: " << (int)type->id);
return false;
}
ConfigDescription config;
config.copyFromDtoH(type->config);
- const std::string type_str = util::GetString(type_pool_, type->id - 1);
- const ResourceType* parsed_type = ParseResourceType(type_str);
+ const std::string type_str = android::util::GetString(type_pool_, type->id - 1);
+ std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(type_str);
if (!parsed_type) {
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "invalid type name '" << type_str << "' for type with ID " << type->id);
return true;
}
@@ -378,8 +384,9 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
continue;
}
- const ResourceName name(package->name, *parsed_type,
- util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
+ const ResourceName name(
+ package->name, *parsed_type,
+ android::util::GetString(key_pool_, android::util::DeviceToHost32(entry->key.index)));
const ResourceId res_id(package_id, type->id, static_cast<uint16_t>(it.index()));
std::unique_ptr<Value> resource_value;
@@ -390,13 +397,14 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
resource_value = ParseMapEntry(name, config, mapEntry);
} else {
const Res_value* value =
- (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
+ (const Res_value*)((const uint8_t*)entry + android::util::DeviceToHost32(entry->size));
resource_value = ParseValue(name, config, *value);
}
if (!resource_value) {
- diag_->Error(DiagMessage(source_) << "failed to parse value for resource " << name << " ("
- << res_id << ") with configuration '" << config << "'");
+ diag_->Error(android::DiagMessage(source_)
+ << "failed to parse value for resource " << name << " (" << res_id
+ << ") with configuration '" << config << "'");
return false;
}
@@ -450,7 +458,7 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
const size_t count = entries.size();
for (size_t i = 0; i < count; i++) {
table_->included_packages_[entries.valueAt(i)] =
- util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
+ android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
}
return true;
}
@@ -458,36 +466,39 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
const ResTable_overlayable_header* header = ConvertTo<ResTable_overlayable_header>(chunk);
if (!header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_category_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_category_header chunk");
return false;
}
auto overlayable = std::make_shared<Overlayable>();
- overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
- arraysize(header->name)));
- overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
- arraysize(header->name)));
+ overlayable->name = android::util::Utf16ToUtf8(
+ strcpy16_dtoh((const char16_t*)header->name, arraysize(header->name)));
+ overlayable->actor = android::util::Utf16ToUtf8(
+ strcpy16_dtoh((const char16_t*)header->actor, arraysize(header->name)));
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- if (util::DeviceToHost16(parser.chunk()->type) == android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
+ if (android::util::DeviceToHost16(parser.chunk()->type) ==
+ android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
const ResTable_overlayable_policy_header* policy_header =
ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
- ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
- const ResTable_ref* const ref_end = ref_begin
- + util::DeviceToHost32(policy_header->entry_count);
+ ((uint8_t*)policy_header) +
+ android::util::DeviceToHost32(policy_header->header.headerSize));
+ const ResTable_ref* const ref_end =
+ ref_begin + android::util::DeviceToHost32(policy_header->entry_count);
for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
- ResourceId res_id(util::DeviceToHost32(ref_iter->ident));
+ ResourceId res_id(android::util::DeviceToHost32(ref_iter->ident));
const auto iter = id_index_.find(res_id);
// If the overlayable chunk comes before the type chunks, the resource ids and resource name
// pairing will not exist at this point.
if (iter == id_index_.cend()) {
- diag_->Error(DiagMessage(source_) << "failed to find resource name for overlayable"
- << " resource " << res_id);
+ diag_->Error(android::DiagMessage(source_)
+ << "failed to find resource name for overlayable"
+ << " resource " << res_id);
return false;
}
@@ -511,23 +522,23 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseStagedAliases(const ResChunk_header* chunk) {
auto header = ConvertTo<ResTable_staged_alias_header>(chunk);
if (!header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_staged_alias_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_staged_alias_header chunk");
return false;
}
const auto ref_begin = reinterpret_cast<const ResTable_staged_alias_entry*>(
- ((uint8_t*)header) + util::DeviceToHost32(header->header.headerSize));
- const auto ref_end = ref_begin + util::DeviceToHost32(header->count);
+ ((uint8_t*)header) + android::util::DeviceToHost32(header->header.headerSize));
+ const auto ref_end = ref_begin + android::util::DeviceToHost32(header->count);
for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
- const auto staged_id = ResourceId(util::DeviceToHost32(ref_iter->stagedResId));
- const auto finalized_id = ResourceId(util::DeviceToHost32(ref_iter->finalizedResId));
+ const auto staged_id = ResourceId(android::util::DeviceToHost32(ref_iter->stagedResId));
+ const auto finalized_id = ResourceId(android::util::DeviceToHost32(ref_iter->finalizedResId));
// If the staged alias chunk comes before the type chunks, the resource ids and resource name
// pairing will not exist at this point.
const auto iter = id_index_.find(finalized_id);
if (iter == id_index_.cend()) {
- diag_->Error(DiagMessage(source_) << "failed to find resource name for finalized"
- << " resource ID " << finalized_id);
+ diag_->Error(android::DiagMessage(source_) << "failed to find resource name for finalized"
+ << " resource ID " << finalized_id);
return false;
}
@@ -563,9 +574,9 @@ std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& na
if (file_ref != nullptr) {
file_ref->file = files_->FindFile(*file_ref->path);
if (file_ref->file == nullptr) {
- diag_->Warn(DiagMessage() << "resource " << name << " for config '" << config
- << "' is a file reference to '" << *file_ref->path
- << "' but no such path exists");
+ diag_->Warn(android::DiagMessage() << "resource " << name << " for config '" << config
+ << "' is a file reference to '" << *file_ref->path
+ << "' but no such path exists");
}
}
}
@@ -594,8 +605,8 @@ std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef
// We can ignore the value here.
return util::make_unique<Id>();
default:
- diag_->Error(DiagMessage() << "illegal map type '" << name.type << "' ("
- << (int)name.type.type << ")");
+ diag_->Error(android::DiagMessage()
+ << "illegal map type '" << name.type << "' (" << (int)name.type.type << ")");
break;
}
return {};
@@ -605,18 +616,18 @@ std::unique_ptr<Style> BinaryResourceParser::ParseStyle(const ResourceNameRef& n
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Style> style = util::make_unique<Style>();
- if (util::DeviceToHost32(map->parent.ident) != 0) {
+ if (android::util::DeviceToHost32(map->parent.ident) != 0) {
// The parent is a regular reference to a resource.
- style->parent = Reference(util::DeviceToHost32(map->parent.ident));
+ style->parent = Reference(android::util::DeviceToHost32(map->parent.ident));
}
for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
+ if (Res_INTERNALID(android::util::DeviceToHost32(map_entry.name.ident))) {
continue;
}
Style::Entry style_entry;
- style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
+ style_entry.key = Reference(android::util::DeviceToHost32(map_entry.name.ident));
style_entry.value = ParseValue(name, config, map_entry.value);
if (!style_entry.value) {
return {};
@@ -630,20 +641,20 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
- attr->SetWeak((util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
+ attr->SetWeak((android::util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
// First we must discover what type of attribute this is. Find the type mask.
auto type_mask_iter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
- return util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
+ return android::util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
});
if (type_mask_iter != end(map)) {
- attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
+ attr->type_mask = android::util::DeviceToHost32(type_mask_iter->value.data);
}
for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
- switch (util::DeviceToHost32(map_entry.name.ident)) {
+ if (Res_INTERNALID(android::util::DeviceToHost32(map_entry.name.ident))) {
+ switch (android::util::DeviceToHost32(map_entry.name.ident)) {
case ResTable_map::ATTR_MIN:
attr->min_int = static_cast<int32_t>(map_entry.value.data);
break;
@@ -656,9 +667,9 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef
if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Attribute::Symbol symbol;
- symbol.value = util::DeviceToHost32(map_entry.value.data);
+ symbol.value = android::util::DeviceToHost32(map_entry.value.data);
symbol.type = map_entry.value.dataType;
- symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
+ symbol.symbol = Reference(android::util::DeviceToHost32(map_entry.name.ident));
attr->symbols.push_back(std::move(symbol));
}
}
@@ -687,7 +698,7 @@ std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(const ResourceNameRef&
return {};
}
- switch (util::DeviceToHost32(map_entry.name.ident)) {
+ switch (android::util::DeviceToHost32(map_entry.name.ident)) {
case ResTable_map::ATTR_ZERO:
plural->values[Plural::Zero] = std::move(item);
break;
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index 1c83166c5cce..8f6949e7e630 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -19,13 +19,13 @@
#include <string>
+#include "ResourceTable.h"
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-
-#include "ResourceTable.h"
-#include "ResourceValues.h"
-#include "Source.h"
+#include "androidfw/Source.h"
+#include "androidfw/Util.h"
#include "process/IResourceTableConsumer.h"
#include "util/Util.h"
@@ -40,8 +40,9 @@ class BinaryResourceParser {
public:
// Creates a parser, which will read `len` bytes from `data`, and add any resources parsed to
// `table`. `source` is for logging purposes.
- BinaryResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
- const void* data, size_t data_len, io::IFileCollection* files = nullptr);
+ BinaryResourceParser(android::IDiagnostics* diag, ResourceTable* table,
+ const android::Source& source, const void* data, size_t data_len,
+ io::IFileCollection* files = nullptr);
// Parses the binary resource table and returns true if successful.
bool Parse();
@@ -91,10 +92,10 @@ class BinaryResourceParser {
*/
bool CollectMetaData(const android::ResTable_map& map_entry, Value* value);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
ResourceTable* table_;
- const Source source_;
+ const android::Source source_;
const void* data_;
const size_t data_len_;
@@ -132,11 +133,11 @@ namespace android {
// Iterator functionality for ResTable_map_entry.
inline const ResTable_map* begin(const ResTable_map_entry* map) {
- return (const ResTable_map*)((const uint8_t*)map + ::aapt::util::DeviceToHost32(map->size));
+ return (const ResTable_map*)((const uint8_t*)map + android::util::DeviceToHost32(map->size));
}
inline const ResTable_map* end(const ResTable_map_entry* map) {
- return begin(map) + aapt::util::DeviceToHost32(map->count);
+ return begin(map) + android::util::DeviceToHost32(map->count);
}
} // namespace android
diff --git a/tools/aapt2/format/binary/ChunkWriter.h b/tools/aapt2/format/binary/ChunkWriter.h
index 1892a295dcf5..e1a403476ff8 100644
--- a/tools/aapt2/format/binary/ChunkWriter.h
+++ b/tools/aapt2/format/binary/ChunkWriter.h
@@ -18,16 +18,15 @@
#define AAPT_FORMAT_BINARY_CHUNKWRITER_H
#include "android-base/macros.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
-#include "util/BigBuffer.h"
#include "util/Util.h"
namespace aapt {
class ChunkWriter {
public:
- explicit inline ChunkWriter(BigBuffer* buffer) : buffer_(buffer) {
+ explicit inline ChunkWriter(android::BigBuffer* buffer) : buffer_(buffer) {
}
ChunkWriter(ChunkWriter&&) = default;
ChunkWriter& operator=(ChunkWriter&&) = default;
@@ -37,8 +36,8 @@ class ChunkWriter {
start_size_ = buffer_->size();
T* chunk = buffer_->NextBlock<T>();
header_ = &chunk->header;
- header_->type = util::HostToDevice16(type);
- header_->headerSize = util::HostToDevice16(sizeof(T));
+ header_->type = android::util::HostToDevice16(type);
+ header_->headerSize = android::util::HostToDevice16(sizeof(T));
return chunk;
}
@@ -47,7 +46,7 @@ class ChunkWriter {
return buffer_->NextBlock<T>(count);
}
- inline BigBuffer* buffer() {
+ inline android::BigBuffer* buffer() {
return buffer_;
}
@@ -61,14 +60,14 @@ class ChunkWriter {
inline android::ResChunk_header* Finish() {
buffer_->Align4();
- header_->size = util::HostToDevice32(buffer_->size() - start_size_);
+ header_->size = android::util::HostToDevice32(buffer_->size() - start_size_);
return header_;
}
private:
DISALLOW_COPY_AND_ASSIGN(ChunkWriter);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
size_t start_size_ = 0;
android::ResChunk_header* header_ = nullptr;
};
@@ -77,8 +76,8 @@ template <>
inline android::ResChunk_header* ChunkWriter::StartChunk(uint16_t type) {
start_size_ = buffer_->size();
header_ = buffer_->NextBlock<android::ResChunk_header>();
- header_->type = util::HostToDevice16(type);
- header_->headerSize = util::HostToDevice16(sizeof(android::ResChunk_header));
+ header_->type = android::util::HostToDevice16(type);
+ header_->headerSize = android::util::HostToDevice16(sizeof(android::ResChunk_header));
return header_;
}
diff --git a/tools/aapt2/format/binary/ResChunkPullParser.cpp b/tools/aapt2/format/binary/ResChunkPullParser.cpp
index fd6919d1de60..2f3df5cae829 100644
--- a/tools/aapt2/format/binary/ResChunkPullParser.cpp
+++ b/tools/aapt2/format/binary/ResChunkPullParser.cpp
@@ -17,12 +17,13 @@
#include "format/binary/ResChunkPullParser.h"
#include <inttypes.h>
+
#include <cstddef>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
-
+#include "androidfw/Util.h"
#include "util/Util.h"
namespace aapt {
@@ -32,8 +33,9 @@ using android::base::StringPrintf;
static std::string ChunkHeaderDump(const ResChunk_header* header) {
return StringPrintf("(type=%02" PRIx16 " header_size=%" PRIu16 " size=%" PRIu32 ")",
- util::DeviceToHost16(header->type), util::DeviceToHost16(header->headerSize),
- util::DeviceToHost32(header->size));
+ android::util::DeviceToHost16(header->type),
+ android::util::DeviceToHost16(header->headerSize),
+ android::util::DeviceToHost32(header->size));
}
ResChunkPullParser::Event ResChunkPullParser::Next() {
@@ -45,7 +47,7 @@ ResChunkPullParser::Event ResChunkPullParser::Next() {
current_chunk_ = data_;
} else {
current_chunk_ = (const ResChunk_header*)(((const char*)current_chunk_) +
- util::DeviceToHost32(current_chunk_->size));
+ android::util::DeviceToHost32(current_chunk_->size));
}
const std::ptrdiff_t diff = (const char*)current_chunk_ - (const char*)data_;
@@ -61,16 +63,16 @@ ResChunkPullParser::Event ResChunkPullParser::Next() {
return (event_ = Event::kBadDocument);
}
- if (util::DeviceToHost16(current_chunk_->headerSize) < sizeof(ResChunk_header)) {
+ if (android::util::DeviceToHost16(current_chunk_->headerSize) < sizeof(ResChunk_header)) {
error_ = "chunk has too small header";
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
- } else if (util::DeviceToHost32(current_chunk_->size) <
- util::DeviceToHost16(current_chunk_->headerSize)) {
+ } else if (android::util::DeviceToHost32(current_chunk_->size) <
+ android::util::DeviceToHost16(current_chunk_->headerSize)) {
error_ = "chunk's total size is smaller than header " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
- } else if (offset + util::DeviceToHost32(current_chunk_->size) > len_) {
+ } else if (offset + android::util::DeviceToHost32(current_chunk_->size) > len_) {
error_ = "chunk's data extends past the end of the document " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
diff --git a/tools/aapt2/format/binary/ResChunkPullParser.h b/tools/aapt2/format/binary/ResChunkPullParser.h
index 5ff13598a31d..0f46db1876fb 100644
--- a/tools/aapt2/format/binary/ResChunkPullParser.h
+++ b/tools/aapt2/format/binary/ResChunkPullParser.h
@@ -21,7 +21,7 @@
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
-
+#include "androidfw/Util.h"
#include "util/Util.h"
namespace aapt {
@@ -69,18 +69,19 @@ class ResChunkPullParser {
template <typename T, size_t MinSize = sizeof(T)>
inline static const T* ConvertTo(const android::ResChunk_header* chunk) {
- if (util::DeviceToHost16(chunk->headerSize) < MinSize) {
+ if (android::util::DeviceToHost16(chunk->headerSize) < MinSize) {
return nullptr;
}
return reinterpret_cast<const T*>(chunk);
}
inline static const uint8_t* GetChunkData(const android::ResChunk_header* chunk) {
- return reinterpret_cast<const uint8_t*>(chunk) + util::DeviceToHost16(chunk->headerSize);
+ return reinterpret_cast<const uint8_t*>(chunk) + android::util::DeviceToHost16(chunk->headerSize);
}
inline static uint32_t GetChunkDataLen(const android::ResChunk_header* chunk) {
- return util::DeviceToHost32(chunk->size) - util::DeviceToHost16(chunk->headerSize);
+ return android::util::DeviceToHost32(chunk->size) -
+ android::util::DeviceToHost16(chunk->headerSize);
}
//
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index a9192e889c17..cd07b1ebbf92 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -21,19 +21,18 @@
#include <sstream>
#include <type_traits>
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/ResourceUtils.h"
-
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/BigBuffer.h"
+#include "androidfw/ResourceUtils.h"
#include "format/binary/ChunkWriter.h"
#include "format/binary/ResourceTypeExtensions.h"
#include "trace/TraceBuffer.h"
-#include "util/BigBuffer.h"
using namespace android;
@@ -54,7 +53,7 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
size_t i;
const char16_t* src_data = src.data();
for (i = 0; i < len - 1 && i < src.size(); i++) {
- dst[i] = util::HostToDevice16((uint16_t)src_data[i]);
+ dst[i] = android::util::HostToDevice16((uint16_t)src_data[i]);
}
dst[i] = 0;
}
@@ -116,7 +115,7 @@ class MapFlattenVisitor : public ConstValueVisitor {
if (style->parent) {
const Reference& parent_ref = style->parent.value();
CHECK(bool(parent_ref.id)) << "parent has no ID";
- out_entry_->parent.ident = util::HostToDevice32(parent_ref.id.value().id);
+ out_entry_->parent.ident = android::util::HostToDevice32(parent_ref.id.value().id);
}
// Sort the style.
@@ -195,7 +194,7 @@ class MapFlattenVisitor : public ConstValueVisitor {
* needs to be done to prepare the entry.
*/
void Finish() {
- out_entry_->count = util::HostToDevice32(entry_count_);
+ out_entry_->count = android::util::HostToDevice32(entry_count_);
}
private:
@@ -203,7 +202,7 @@ class MapFlattenVisitor : public ConstValueVisitor {
void FlattenKey(const Reference* key, ResTable_map* out_entry) {
CHECK(bool(key->id)) << "key has no ID";
- out_entry->name.ident = util::HostToDevice32(key->id.value().id);
+ out_entry->name.ident = android::util::HostToDevice32(key->id.value().id);
}
void FlattenValue(const Item* value, ResTable_map* out_entry) {
@@ -214,7 +213,7 @@ class MapFlattenVisitor : public ConstValueVisitor {
ResTable_map* out_entry = buffer_->NextBlock<ResTable_map>();
FlattenKey(key, out_entry);
FlattenValue(value, out_entry);
- out_entry->value.size = util::HostToDevice16(sizeof(out_entry->value));
+ out_entry->value.size = android::util::HostToDevice16(sizeof(out_entry->value));
entry_count_++;
}
@@ -225,7 +224,7 @@ class MapFlattenVisitor : public ConstValueVisitor {
struct OverlayableChunk {
std::string actor;
- Source source;
+ android::Source source;
std::map<PolicyFlags, std::set<ResourceId>> policy_ids;
};
@@ -248,31 +247,33 @@ class PackageFlattener {
TRACE_CALL();
ChunkWriter pkg_writer(buffer);
ResTable_package* pkg_header = pkg_writer.StartChunk<ResTable_package>(RES_TABLE_PACKAGE_TYPE);
- pkg_header->id = util::HostToDevice32(package_.id.value());
+ pkg_header->id = android::util::HostToDevice32(package_.id.value());
// AAPT truncated the package name, so do the same.
// Shared libraries require full package names, so don't truncate theirs.
if (context_->GetPackageType() != PackageType::kApp &&
package_.name.size() >= arraysize(pkg_header->name)) {
- diag_->Error(DiagMessage() << "package name '" << package_.name
- << "' is too long. "
- "Shared libraries cannot have truncated package names");
+ diag_->Error(android::DiagMessage()
+ << "package name '" << package_.name
+ << "' is too long. "
+ "Shared libraries cannot have truncated package names");
return false;
}
// Copy the package name in device endianness.
- strcpy16_htod(pkg_header->name, arraysize(pkg_header->name), util::Utf8ToUtf16(package_.name));
+ strcpy16_htod(pkg_header->name, arraysize(pkg_header->name),
+ android::util::Utf8ToUtf16(package_.name));
// Serialize the types. We do this now so that our type and key strings
// are populated. We write those first.
- BigBuffer type_buffer(1024);
+ android::BigBuffer type_buffer(1024);
FlattenTypes(&type_buffer);
- pkg_header->typeStrings = util::HostToDevice32(pkg_writer.size());
- StringPool::FlattenUtf16(pkg_writer.buffer(), type_pool_, diag_);
+ pkg_header->typeStrings = android::util::HostToDevice32(pkg_writer.size());
+ android::StringPool::FlattenUtf16(pkg_writer.buffer(), type_pool_, diag_);
- pkg_header->keyStrings = util::HostToDevice32(pkg_writer.size());
- StringPool::FlattenUtf8(pkg_writer.buffer(), key_pool_, diag_);
+ pkg_header->keyStrings = android::util::HostToDevice32(pkg_writer.size());
+ android::StringPool::FlattenUtf8(pkg_writer.buffer(), key_pool_, diag_);
// Append the types.
buffer->AppendBuffer(std::move(type_buffer));
@@ -317,9 +318,9 @@ class PackageFlattener {
out_entry->flags |= ResTable_entry::FLAG_COMPLEX;
}
- out_entry->flags = util::HostToDevice16(out_entry->flags);
- out_entry->key.index = util::HostToDevice32(entry->entry_key);
- out_entry->size = util::HostToDevice16(sizeof(T));
+ out_entry->flags = android::util::HostToDevice16(out_entry->flags);
+ out_entry->key.index = android::util::HostToDevice32(entry->entry_key);
+ out_entry->size = android::util::HostToDevice16(sizeof(T));
return result;
}
@@ -328,7 +329,7 @@ class PackageFlattener {
WriteEntry<ResTable_entry, true>(entry, buffer);
Res_value* outValue = buffer->NextBlock<Res_value>();
CHECK(item->Flatten(outValue)) << "flatten failed";
- outValue->size = util::HostToDevice16(sizeof(*outValue));
+ outValue->size = android::util::HostToDevice16(sizeof(*outValue));
} else {
ResTable_entry_ext* out_entry = WriteEntry<ResTable_entry_ext, false>(entry, buffer);
MapFlattenVisitor visitor(out_entry, buffer);
@@ -353,14 +354,14 @@ class PackageFlattener {
std::vector<uint32_t> offsets;
offsets.resize(num_total_entries, 0xffffffffu);
- BigBuffer values_buffer(512);
+ android::BigBuffer values_buffer(512);
for (FlatEntry& flat_entry : *entries) {
CHECK(static_cast<size_t>(flat_entry.entry->id.value()) < num_total_entries);
offsets[flat_entry.entry->id.value()] = values_buffer.size();
if (!FlattenValue(&flat_entry, &values_buffer)) {
- diag_->Error(DiagMessage()
+ diag_->Error(android::DiagMessage()
<< "failed to flatten resource '"
- << ResourceNameRef(package_.name, type.type, flat_entry.entry->name)
+ << ResourceNameRef(package_.name, type.named_type, flat_entry.entry->name)
<< "' for configuration '" << config << "'");
return false;
}
@@ -382,27 +383,27 @@ class PackageFlattener {
sparse_encode && ((100 * entries->size()) / num_total_entries) < kSparseEncodingThreshold;
if (sparse_encode) {
- type_header->entryCount = util::HostToDevice32(entries->size());
+ type_header->entryCount = android::util::HostToDevice32(entries->size());
type_header->flags |= ResTable_type::FLAG_SPARSE;
ResTable_sparseTypeEntry* indices =
type_writer.NextBlock<ResTable_sparseTypeEntry>(entries->size());
for (size_t i = 0; i < num_total_entries; i++) {
if (offsets[i] != ResTable_type::NO_ENTRY) {
CHECK((offsets[i] & 0x03) == 0);
- indices->idx = util::HostToDevice16(i);
- indices->offset = util::HostToDevice16(offsets[i] / 4u);
+ indices->idx = android::util::HostToDevice16(i);
+ indices->offset = android::util::HostToDevice16(offsets[i] / 4u);
indices++;
}
}
} else {
- type_header->entryCount = util::HostToDevice32(num_total_entries);
+ type_header->entryCount = android::util::HostToDevice32(num_total_entries);
uint32_t* indices = type_writer.NextBlock<uint32_t>(num_total_entries);
for (size_t i = 0; i < num_total_entries; i++) {
- indices[i] = util::HostToDevice32(offsets[i]);
+ indices[i] = android::util::HostToDevice32(offsets[i]);
}
}
- type_header->entriesStart = util::HostToDevice32(type_writer.size());
+ type_header->entriesStart = android::util::HostToDevice32(type_writer.size());
type_writer.buffer()->AppendBuffer(std::move(values_buffer));
type_writer.Finish();
return true;
@@ -416,12 +417,12 @@ class PackageFlattener {
ChunkWriter alias_writer(buffer);
auto header =
alias_writer.StartChunk<ResTable_staged_alias_header>(RES_TABLE_STAGED_ALIAS_TYPE);
- header->count = util::HostToDevice32(aliases_.size());
+ header->count = android::util::HostToDevice32(aliases_.size());
auto mapping = alias_writer.NextBlock<ResTable_staged_alias_entry>(aliases_.size());
for (auto& p : aliases_) {
- mapping->stagedResId = util::HostToDevice32(p.first);
- mapping->finalizedResId = util::HostToDevice32(p.second);
+ mapping->stagedResId = android::util::HostToDevice32(p.first);
+ mapping->finalizedResId = android::util::HostToDevice32(p.second);
++mapping;
}
alias_writer.Finish();
@@ -447,7 +448,7 @@ class PackageFlattener {
ResourceId id = android::make_resid(package_.id.value(), type.id.value(), entry.id.value());
CHECK(seen_ids.find(id) == seen_ids.end())
<< "multiple overlayable definitions found for resource "
- << ResourceName(package_.name, type.type, entry.name).to_string();
+ << ResourceName(package_.name, type.named_type, entry.name).to_string();
seen_ids.insert(id);
// Find the overlayable chunk with the specified name
@@ -461,11 +462,11 @@ class PackageFlattener {
OverlayableChunk& chunk = iter->second;
if (!(chunk.source == item.overlayable->source)) {
// The name of an overlayable set of resources must be unique
- context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
- << "duplicate overlayable name"
- << item.overlayable->name << "'");
- context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
- << "previous declaration here");
+ context_->GetDiagnostics()->Error(android::DiagMessage(item.overlayable->source)
+ << "duplicate overlayable name"
+ << item.overlayable->name << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage(chunk.source)
+ << "previous declaration here");
return false;
}
@@ -474,7 +475,7 @@ class PackageFlattener {
}
if (item.policies == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+ context_->GetDiagnostics()->Error(android::DiagMessage(item.overlayable->source)
<< "overlayable " << entry.name
<< " does not specify policy");
return false;
@@ -499,38 +500,36 @@ class PackageFlattener {
auto* overlayable_type =
overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
if (name.size() >= arraysize(overlayable_type->name)) {
- diag_->Error(DiagMessage() << "overlayable name '" << name
- << "' exceeds maximum length ("
- << arraysize(overlayable_type->name)
- << " utf16 characters)");
+ diag_->Error(android::DiagMessage()
+ << "overlayable name '" << name << "' exceeds maximum length ("
+ << arraysize(overlayable_type->name) << " utf16 characters)");
return false;
}
strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
- util::Utf8ToUtf16(name));
+ android::util::Utf8ToUtf16(name));
if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
- diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
- << "' exceeds maximum length ("
- << arraysize(overlayable_type->actor)
- << " utf16 characters)");
+ diag_->Error(android::DiagMessage()
+ << "overlayable name '" << overlayable.actor << "' exceeds maximum length ("
+ << arraysize(overlayable_type->actor) << " utf16 characters)");
return false;
}
strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
- util::Utf8ToUtf16(overlayable.actor));
+ android::util::Utf8ToUtf16(overlayable.actor));
// Write each policy block for the overlayable
for (auto& policy_ids : overlayable.policy_ids) {
ChunkWriter policy_writer(buffer);
auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
RES_TABLE_OVERLAYABLE_POLICY_TYPE);
- policy_type->policy_flags =
- static_cast<PolicyFlags>(util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)));
- policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
- policy_ids.second.size()));
+ policy_type->policy_flags = static_cast<PolicyFlags>(
+ android::util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)));
+ policy_type->entry_count =
+ android::util::HostToDevice32(static_cast<uint32_t>(policy_ids.second.size()));
// Write the ids after the policy header
auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
for (const ResourceId& id : policy_ids.second) {
- id_block->ident = util::HostToDevice32(id.id);
+ id_block->ident = android::util::HostToDevice32(id.id);
id_block++;
}
policy_writer.Finish();
@@ -559,7 +558,7 @@ class PackageFlattener {
// Since the entries are sorted by ID, the last one will be the biggest.
const size_t num_entries = sorted_entries.back().id.value() + 1;
- spec_header->entryCount = util::HostToDevice32(num_entries);
+ spec_header->entryCount = android::util::HostToDevice32(num_entries);
// Reserve space for the masks of each resource in this type. These
// show for which configuration axis the resource changes.
@@ -571,17 +570,18 @@ class PackageFlattener {
// Populate the config masks for this entry.
uint32_t& entry_config_masks = config_masks[entry_id];
if (entry.visibility.level == Visibility::Level::kPublic) {
- entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
+ entry_config_masks |= android::util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
if (entry.visibility.staged_api) {
- entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_STAGED_API);
+ entry_config_masks |= android::util::HostToDevice32(ResTable_typeSpec::SPEC_STAGED_API);
}
const size_t config_count = entry.values.size();
for (size_t i = 0; i < config_count; i++) {
const ConfigDescription& config = entry.values[i]->config;
for (size_t j = i + 1; j < config_count; j++) {
- config_masks[entry_id] |= util::HostToDevice32(config.diff(entry.values[j]->config));
+ config_masks[entry_id] |=
+ android::util::HostToDevice32(config.diff(entry.values[j]->config));
}
}
}
@@ -592,7 +592,8 @@ class PackageFlattener {
bool FlattenTypes(BigBuffer* buffer) {
size_t expected_type_id = 1;
for (const ResourceTableTypeView& type : package_.types) {
- if (type.type == ResourceType::kStyleable || type.type == ResourceType::kMacro) {
+ if (type.named_type.type == ResourceType::kStyleable ||
+ type.named_type.type == ResourceType::kMacro) {
// Styleables and macros are not real resource types.
continue;
}
@@ -606,7 +607,7 @@ class PackageFlattener {
expected_type_id++;
}
expected_type_id++;
- type_pool_.MakeRef(to_string(type.type));
+ type_pool_.MakeRef(type.named_type.to_string());
if (!FlattenTypeSpec(type, type.entries, buffer)) {
return false;
@@ -634,7 +635,7 @@ class PackageFlattener {
}
uint32_t local_key_index;
- ResourceName resource_name({}, type.type, entry.name);
+ ResourceName resource_name({}, type.named_type, entry.name);
if (!collapse_key_stringpool_ ||
name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
@@ -667,33 +668,33 @@ class PackageFlattener {
const size_t num_entries = (package_.id.value() == 0x00 ? 1 : 0) + shared_libs_->size();
CHECK(num_entries > 0);
- lib_header->count = util::HostToDevice32(num_entries);
+ lib_header->count = android::util::HostToDevice32(num_entries);
ResTable_lib_entry* lib_entry = buffer->NextBlock<ResTable_lib_entry>(num_entries);
if (package_.id.value() == 0x00) {
// Add this package
- lib_entry->packageId = util::HostToDevice32(0x00);
+ lib_entry->packageId = android::util::HostToDevice32(0x00);
strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
- util::Utf8ToUtf16(package_.name));
+ android::util::Utf8ToUtf16(package_.name));
++lib_entry;
}
for (auto& map_entry : *shared_libs_) {
- lib_entry->packageId = util::HostToDevice32(map_entry.first);
+ lib_entry->packageId = android::util::HostToDevice32(map_entry.first);
strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
- util::Utf8ToUtf16(map_entry.second));
+ android::util::Utf8ToUtf16(map_entry.second));
++lib_entry;
}
lib_writer.Finish();
}
IAaptContext* context_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
const ResourceTablePackageView package_;
const std::map<size_t, std::string>* shared_libs_;
bool use_sparse_entries_;
- StringPool type_pool_;
- StringPool key_pool_;
+ android::StringPool type_pool_;
+ android::StringPool key_pool_;
bool collapse_key_stringpool_;
const std::set<ResourceName>& name_collapse_exemptions_;
std::map<uint32_t, uint32_t> aliases_;
@@ -705,26 +706,27 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
TRACE_CALL();
// We must do this before writing the resources, since the string pool IDs may change.
table->string_pool.Prune();
- table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
- int diff = util::compare(a.priority, b.priority);
- if (diff == 0) {
- diff = a.config.compare(b.config);
- }
- return diff;
- });
+ table->string_pool.Sort(
+ [](const android::StringPool::Context& a, const android::StringPool::Context& b) -> int {
+ int diff = util::compare(a.priority, b.priority);
+ if (diff == 0) {
+ diff = a.config.compare(b.config);
+ }
+ return diff;
+ });
// Write the ResTable header.
const auto& table_view =
table->GetPartitionedView(ResourceTableViewOptions{.create_alias_entries = true});
ChunkWriter table_writer(buffer_);
ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
- table_header->packageCount = util::HostToDevice32(table_view.packages.size());
+ table_header->packageCount = android::util::HostToDevice32(table_view.packages.size());
// Flatten the values string pool.
- StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool,
- context->GetDiagnostics());
+ android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool,
+ context->GetDiagnostics());
- BigBuffer package_buffer(1024);
+ android::BigBuffer package_buffer(1024);
// Flatten each package.
for (auto& package : table_view.packages) {
@@ -737,7 +739,7 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
if (!result.second && result.first->second != package.name) {
// A mapping for this package ID already exists, and is a different package. Error!
context->GetDiagnostics()->Error(
- DiagMessage() << android::base::StringPrintf(
+ android::DiagMessage() << android::base::StringPrintf(
"can't map package ID %02x to '%s'. Already mapped to '%s'", package_id,
package.name.c_str(), result.first->second.c_str()));
return false;
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 4360db190146..1eec0e4d8c51 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -17,12 +17,11 @@
#ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H
#define AAPT_FORMAT_BINARY_TABLEFLATTENER_H
-#include "android-base/macros.h"
-
#include "Resource.h"
#include "ResourceTable.h"
+#include "android-base/macros.h"
+#include "androidfw/BigBuffer.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
namespace aapt {
@@ -51,7 +50,7 @@ struct TableFlattenerOptions {
class TableFlattener : public IResourceTableConsumer {
public:
- explicit TableFlattener(const TableFlattenerOptions& options, BigBuffer* buffer)
+ explicit TableFlattener(const TableFlattenerOptions& options, android::BigBuffer* buffer)
: options_(options), buffer_(buffer) {
}
@@ -61,7 +60,7 @@ class TableFlattener : public IResourceTableConsumer {
DISALLOW_COPY_AND_ASSIGN(TableFlattener);
TableFlattenerOptions options_;
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
};
} // namespace aapt
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index cd1c0af702cf..1dd2468b5868 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -45,7 +45,7 @@ class TableFlattenerTest : public ::testing::Test {
::testing::AssertionResult Flatten(IAaptContext* context, const TableFlattenerOptions& options,
ResourceTable* table, std::string* out_content) {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
TableFlattener flattener(options, &buffer);
if (!flattener.Consume(context, table)) {
return ::testing::AssertionFailure() << "failed to flatten ResourceTable";
@@ -254,13 +254,13 @@ TEST_F(TableFlattenerTest, FlattenArray) {
// Parse the flattened resource table
ResChunkPullParser parser(result.data(), result.size());
ASSERT_TRUE(parser.IsGoodEvent(parser.Next()));
- ASSERT_EQ(util::DeviceToHost16(parser.chunk()->type), RES_TABLE_TYPE);
+ ASSERT_EQ(android::util::DeviceToHost16(parser.chunk()->type), RES_TABLE_TYPE);
// Retrieve the package of the entry
ResChunkPullParser table_parser(GetChunkData(parser.chunk()), GetChunkDataLen(parser.chunk()));
const ResChunk_header* package_chunk = nullptr;
while (table_parser.IsGoodEvent(table_parser.Next())) {
- if (util::DeviceToHost16(table_parser.chunk()->type) == RES_TABLE_PACKAGE_TYPE) {
+ if (android::util::DeviceToHost16(table_parser.chunk()->type) == RES_TABLE_PACKAGE_TYPE) {
package_chunk = table_parser.chunk();
break;
}
@@ -272,7 +272,7 @@ TEST_F(TableFlattenerTest, FlattenArray) {
GetChunkDataLen(table_parser.chunk()));
const ResChunk_header* type_chunk = nullptr;
while (package_parser.IsGoodEvent(package_parser.Next())) {
- if (util::DeviceToHost16(package_parser.chunk()->type) == RES_TABLE_TYPE_TYPE) {
+ if (android::util::DeviceToHost16(package_parser.chunk()->type) == RES_TABLE_TYPE_TYPE) {
type_chunk = package_parser.chunk();
break;
}
@@ -282,7 +282,7 @@ TEST_F(TableFlattenerTest, FlattenArray) {
ASSERT_NE(type_chunk, nullptr);
TypeVariant typeVariant((const ResTable_type*) type_chunk);
auto entry = (const ResTable_map_entry*)*typeVariant.beginEntries();
- ASSERT_EQ(util::DeviceToHost16(entry->count), 2u);
+ ASSERT_EQ(android::util::DeviceToHost16(entry->count), 2u);
// Check that the value and name of the array entries are correct
auto values = (const ResTable_map*)(((const uint8_t *)entry) + entry->size);
@@ -837,4 +837,45 @@ TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table));
}
+TEST_F(TableFlattenerTest, FlattenCustomResourceTypes) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/one", ResourceId(0x7f010000))
+ .AddSimple("com.app.test:id.2/two", ResourceId(0x7f020000))
+ .AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 10u))
+ .AddValue("com.app.test:integer.1/one", ResourceId(0x7f040000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ .AddValue("com.app.test:integer.1/one", test::ParseConfigOrDie("v1"),
+ ResourceId(0x7f040000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ .AddString("com.app.test:layout.custom/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
+ .Build();
+
+ ResTable res_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f010000), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id.2/two", ResourceId(0x7f020000), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one", ResourceId(0x7f030000), {},
+ Res_value::TYPE_INT_DEC, 10u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000), {},
+ Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000),
+ test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u,
+ ResTable_config::CONFIG_VERSION));
+
+ std::u16string bar_path = u"res/layout/bar.xml";
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
+ ASSERT_TRUE(idx.has_value());
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout.custom/bar", ResourceId(0x7f050000), {},
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index cdbe8828b29b..983e6467fab0 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -64,11 +64,11 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
public:
using xml::ConstVisitor::Visit;
- StringPool pool;
- std::map<uint8_t, StringPool> package_pools;
+ android::StringPool pool;
+ std::map<uint8_t, android::StringPool> package_pools;
struct StringFlattenDest {
- StringPool::Ref ref;
+ android::StringPool::Ref ref;
ResStringPool_ref* dest;
};
@@ -96,8 +96,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter writer(buffer_);
ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE);
- flat_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_node->comment.index = util::HostToDevice32(-1);
+ flat_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>();
AddString(text, kLowPriority, &flat_text->data);
@@ -116,8 +116,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter start_writer(buffer_);
ResXMLTree_node* flat_node =
start_writer.StartChunk<ResXMLTree_node>(RES_XML_START_ELEMENT_TYPE);
- flat_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_node->comment.index = util::HostToDevice32(-1);
+ flat_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_attrExt* flat_elem = start_writer.NextBlock<ResXMLTree_attrExt>();
@@ -126,8 +126,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
true /* treat_empty_string_as_null */);
AddString(node->name, kLowPriority, &flat_elem->name, true /* treat_empty_string_as_null */);
- flat_elem->attributeStart = util::HostToDevice16(sizeof(*flat_elem));
- flat_elem->attributeSize = util::HostToDevice16(sizeof(ResXMLTree_attribute));
+ flat_elem->attributeStart = android::util::HostToDevice16(sizeof(*flat_elem));
+ flat_elem->attributeSize = android::util::HostToDevice16(sizeof(ResXMLTree_attribute));
WriteAttributes(node, flat_elem, &start_writer);
@@ -140,8 +140,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter end_writer(buffer_);
ResXMLTree_node* flat_end_node =
end_writer.StartChunk<ResXMLTree_node>(RES_XML_END_ELEMENT_TYPE);
- flat_end_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_end_node->comment.index = util::HostToDevice32(-1);
+ flat_end_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_end_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_endElementExt* flat_end_elem = end_writer.NextBlock<ResXMLTree_endElementExt>();
AddString(node->namespace_uri, kLowPriority, &flat_end_elem->ns,
@@ -169,17 +169,17 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
bool treat_empty_string_as_null = false) {
if (str.empty() && treat_empty_string_as_null) {
// Some parts of the runtime treat null differently than empty string.
- dest->index = util::DeviceToHost32(-1);
+ dest->index = android::util::DeviceToHost32(-1);
} else {
string_refs.push_back(
- StringFlattenDest{pool.MakeRef(str, StringPool::Context(priority)), dest});
+ StringFlattenDest{pool.MakeRef(str, android::StringPool::Context(priority)), dest});
}
}
// We are adding strings to a StringPool whose strings will be sorted and merged with other
// string pools. That means we can't encode the ID of a string directly. Instead, we defer the
// writing of the ID here, until after the StringPool is merged and sorted.
- void AddString(const StringPool::Ref& ref, android::ResStringPool_ref* dest) {
+ void AddString(const android::StringPool::Ref& ref, android::ResStringPool_ref* dest) {
string_refs.push_back(StringFlattenDest{ref, dest});
}
@@ -187,8 +187,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter writer(buffer_);
ResXMLTree_node* flatNode = writer.StartChunk<ResXMLTree_node>(type);
- flatNode->lineNumber = util::HostToDevice32(decl.line_number);
- flatNode->comment.index = util::HostToDevice32(-1);
+ flatNode->lineNumber = android::util::HostToDevice32(decl.line_number);
+ flatNode->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_namespaceExt* flat_ns = writer.NextBlock<ResXMLTree_namespaceExt>();
AddString(decl.prefix, kLowPriority, &flat_ns->prefix);
@@ -217,7 +217,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
std::sort(filtered_attrs_.begin(), filtered_attrs_.end(), cmp_xml_attribute_by_id);
- flat_elem->attributeCount = util::HostToDevice16(filtered_attrs_.size());
+ flat_elem->attributeCount = android::util::HostToDevice16(filtered_attrs_.size());
ResXMLTree_attribute* flat_attr =
writer->NextBlock<ResXMLTree_attribute>(filtered_attrs_.size());
@@ -226,12 +226,12 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// Assign the indices for specific attributes.
if (xml_attr->compiled_attribute && xml_attr->compiled_attribute.value().id &&
xml_attr->compiled_attribute.value().id.value() == kIdAttr) {
- flat_elem->idIndex = util::HostToDevice16(attribute_index);
+ flat_elem->idIndex = android::util::HostToDevice16(attribute_index);
} else if (xml_attr->namespace_uri.empty()) {
if (xml_attr->name == "class") {
- flat_elem->classIndex = util::HostToDevice16(attribute_index);
+ flat_elem->classIndex = android::util::HostToDevice16(attribute_index);
} else if (xml_attr->name == "style") {
- flat_elem->styleIndex = util::HostToDevice16(attribute_index);
+ flat_elem->styleIndex = android::util::HostToDevice16(attribute_index);
}
}
attribute_index++;
@@ -241,7 +241,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
AddString(xml_attr->namespace_uri, kLowPriority, &flat_attr->ns,
true /* treat_empty_string_as_null */);
- flat_attr->rawValue.index = util::HostToDevice32(-1);
+ flat_attr->rawValue.index = android::util::HostToDevice32(-1);
if (!xml_attr->compiled_attribute || !xml_attr->compiled_attribute.value().id) {
// The attribute has no associated ResourceID, so the string order doesn't matter.
@@ -256,8 +256,9 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// Lookup the StringPool for this package and make the reference there.
const xml::AaptAttribute& aapt_attr = xml_attr->compiled_attribute.value();
- StringPool::Ref name_ref = package_pools[aapt_attr.id.value().package_id()].MakeRef(
- xml_attr->name, StringPool::Context(aapt_attr.id.value().id));
+ android::StringPool::Ref name_ref =
+ package_pools[aapt_attr.id.value().package_id()].MakeRef(
+ xml_attr->name, android::StringPool::Context(aapt_attr.id.value().id));
// Add it to the list of strings to flatten.
AddString(name_ref, &flat_attr->name);
@@ -298,7 +299,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue);
}
- flat_attr->typedValue.size = util::HostToDevice16(sizeof(flat_attr->typedValue));
+ flat_attr->typedValue.size = android::util::HostToDevice16(sizeof(flat_attr->typedValue));
flat_attr++;
}
}
@@ -313,7 +314,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
} // namespace
bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
- BigBuffer node_buffer(1024);
+ android::BigBuffer node_buffer(1024);
XmlFlattenerVisitor visitor(&node_buffer, options_);
node->Accept(&visitor);
@@ -323,13 +324,14 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
}
// Sort the string pool so that attribute resource IDs show up first.
- visitor.pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
- return util::compare(a.priority, b.priority);
- });
+ visitor.pool.Sort(
+ [](const android::StringPool::Context& a, const android::StringPool::Context& b) -> int {
+ return util::compare(a.priority, b.priority);
+ });
// Now we flatten the string pool references into the correct places.
for (const auto& ref_entry : visitor.string_refs) {
- ref_entry.dest->index = util::HostToDevice32(ref_entry.ref.index());
+ ref_entry.dest->index = android::util::HostToDevice32(ref_entry.ref.index());
}
// Write the XML header.
@@ -338,9 +340,9 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
// Flatten the StringPool.
if (options_.use_utf16) {
- StringPool::FlattenUtf16(buffer_, visitor.pool, context->GetDiagnostics());
+ android::StringPool::FlattenUtf16(buffer_, visitor.pool, context->GetDiagnostics());
} else {
- StringPool::FlattenUtf8(buffer_, visitor.pool, context->GetDiagnostics());
+ android::StringPool::FlattenUtf8(buffer_, visitor.pool, context->GetDiagnostics());
}
{
@@ -353,7 +355,7 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
// When we see the first non-resource ID, we're done.
break;
}
- *res_id_map_writer.NextBlock<uint32_t>() = util::HostToDevice32(id.id);
+ *res_id_map_writer.NextBlock<uint32_t>() = android::util::HostToDevice32(id.id);
}
res_id_map_writer.Finish();
}
diff --git a/tools/aapt2/format/binary/XmlFlattener.h b/tools/aapt2/format/binary/XmlFlattener.h
index 1f9e777f7a1a..e18c1e5b3fe1 100644
--- a/tools/aapt2/format/binary/XmlFlattener.h
+++ b/tools/aapt2/format/binary/XmlFlattener.h
@@ -18,9 +18,8 @@
#define AAPT_FORMAT_BINARY_XMLFLATTENER_H
#include "android-base/macros.h"
-
+#include "androidfw/BigBuffer.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -36,7 +35,7 @@ struct XmlFlattenerOptions {
class XmlFlattener {
public:
- XmlFlattener(BigBuffer* buffer, XmlFlattenerOptions options)
+ XmlFlattener(android::BigBuffer* buffer, XmlFlattenerOptions options)
: buffer_(buffer), options_(options) {
}
@@ -47,7 +46,7 @@ class XmlFlattener {
bool Flatten(IAaptContext* context, const xml::Node* node);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
XmlFlattenerOptions options_;
};
diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp
index d97e8882e5a2..6d0022cad307 100644
--- a/tools/aapt2/format/binary/XmlFlattener_test.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp
@@ -16,11 +16,10 @@
#include "format/binary/XmlFlattener.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
#include "link/Linkers.h"
#include "test/Test.h"
-#include "util/BigBuffer.h"
#include "util/Util.h"
using ::aapt::test::StrEq;
@@ -59,13 +58,13 @@ class XmlFlattenerTest : public ::testing::Test {
const XmlFlattenerOptions& options = {}) {
using namespace android; // For NO_ERROR on windows because it is a macro.
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
XmlFlattener flattener(&buffer, options);
if (!flattener.Consume(context_.get(), doc)) {
return ::testing::AssertionFailure() << "failed to flatten XML Tree";
}
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
if (out_tree->setTo(data.get(), buffer.size(), true) != NO_ERROR) {
return ::testing::AssertionFailure() << "flattened XML is corrupt";
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 236c38167545..6a1e8c1bb24c 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -16,15 +16,15 @@
#include "format/proto/ProtoDeserialize.h"
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/Locale.h"
-
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "androidfw/Locale.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
using ::android::ConfigDescription;
using ::android::LocaleValue;
@@ -358,8 +358,8 @@ bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescripti
}
static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool,
- Source* out_source) {
- out_source->path = util::GetString(src_pool, pb_source.path_idx());
+ android::Source* out_source) {
+ out_source->path = android::util::GetString(src_pool, pb_source.path_idx());
out_source->line = static_cast<size_t>(pb_source.position().line_number());
}
@@ -429,8 +429,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
ResourceTablePackage* pkg = out_table->FindOrCreatePackage(pb_package.package_name());
for (const pb::Type& pb_type : pb_package.type()) {
- const ResourceType* res_type = ParseResourceType(pb_type.name());
- if (res_type == nullptr) {
+ auto res_type = ParseResourceNamedType(pb_type.name());
+ if (!res_type) {
std::ostringstream error;
error << "unknown type '" << pb_type.name() << "'";
*out_error = error.str();
@@ -515,7 +515,7 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
pb_entry.entry_id().id());
if (resid.is_valid()) {
- id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
+ id_index[resid] = ResourceNameRef(pkg->name, type->named_type, entry->name);
}
for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
@@ -680,7 +680,7 @@ static bool DeserializeMacroFromPb(const pb::MacroBody& pb_ref, Macro* out_ref,
if (pb_ref.has_style_string()) {
out_ref->style_string.str = pb_ref.style_string().str();
for (const auto& span : pb_ref.style_string().spans()) {
- out_ref->style_string.spans.emplace_back(Span{
+ out_ref->style_string.spans.emplace_back(android::Span{
.name = span.name(), .first_char = span.start_index(), .last_char = span.end_index()});
}
}
@@ -705,7 +705,7 @@ template <typename T>
static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
Value* out_value) {
if (pb_item.has_source()) {
- Source source;
+ android::Source source;
DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
out_value->SetSource(std::move(source));
}
@@ -733,8 +733,8 @@ static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error) {
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error) {
std::unique_ptr<Value> value;
if (pb_value.has_item()) {
value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
@@ -774,7 +774,7 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
}
if (pb_style.has_parent_source()) {
- Source parent_source;
+ android::Source parent_source;
DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
style->parent.value().SetSource(std::move(parent_source));
}
@@ -870,7 +870,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
- const ConfigDescription& config, StringPool* value_pool,
+ const ConfigDescription& config,
+ android::StringPool* value_pool,
io::IFileCollection* files, std::string* out_error) {
switch (pb_item.value_case()) {
case pb::Item::kRef: {
@@ -960,29 +961,32 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
case pb::Item::kStr: {
return util::make_unique<String>(
- value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
+ value_pool->MakeRef(pb_item.str().value(), android::StringPool::Context(config)));
} break;
case pb::Item::kRawStr: {
return util::make_unique<RawString>(
- value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
+ value_pool->MakeRef(pb_item.raw_str().value(), android::StringPool::Context(config)));
} break;
case pb::Item::kStyledStr: {
const pb::StyledString& pb_str = pb_item.styled_str();
- StyleString style_str{pb_str.value()};
+ android::StyleString style_str{pb_str.value()};
for (const pb::StyledString::Span& pb_span : pb_str.span()) {
- style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
+ style_str.spans.push_back(
+ android::Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
}
return util::make_unique<StyledString>(value_pool->MakeRef(
- style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ style_str,
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
} break;
case pb::Item::kFile: {
const pb::FileReference& pb_file = pb_item.file();
std::unique_ptr<FileReference> file_ref =
util::make_unique<FileReference>(value_pool->MakeRef(
- pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+ pb_file.path(),
+ android::StringPool::Context(android::StringPool::Context::kHighPriority, config)));
file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
if (files != nullptr) {
file_ref->file = files->FindFile(*file_ref->path);
@@ -1011,8 +1015,8 @@ std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode
return resource;
}
-bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
- std::string* out_error) {
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el,
+ android::StringPool* value_pool, std::string* out_error) {
const pb::XmlElement& pb_el = pb_node.element();
out_el->name = pb_el.name();
out_el->namespace_uri = pb_el.namespace_uri();
@@ -1042,7 +1046,7 @@ bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, Stri
if (attr.compiled_value == nullptr) {
return {};
}
- attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number()));
+ attr.compiled_value->SetSource(android::Source().WithLine(pb_attr.source().line_number()));
}
out_el->attributes.push_back(std::move(attr));
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index 723a1c095a50..95de3cb52017 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -17,16 +17,15 @@
#ifndef AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
#define AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/ResourceTypes.h"
-
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
-#include "StringPool.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPool.h"
#include "io/File.h"
#include "xml/XmlDom.h"
@@ -35,20 +34,20 @@ namespace aapt {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const android::ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error);
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const android::ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error);
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
std::string* out_error);
-bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
- std::string* out_error);
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el,
+ android::StringPool* value_pool, std::string* out_error);
bool DeserializeConfigFromPb(const pb::Configuration& pb_config,
android::ConfigDescription* out_config, std::string* out_error);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index f3b7f758e170..163a60a9e40e 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -17,7 +17,7 @@
#include "format/proto/ProtoSerialize.h"
#include "ValueVisitor.h"
-#include "util/BigBuffer.h"
+#include "androidfw/BigBuffer.h"
using android::ConfigDescription;
@@ -25,22 +25,24 @@ using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace aapt {
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) {
- BigBuffer buffer(1024);
- StringPool::FlattenUtf8(&buffer, pool, diag);
+void SerializeStringPoolToPb(const android::StringPool& pool, pb::StringPool* out_pb_pool,
+ android::IDiagnostics* diag) {
+ android::BigBuffer buffer(1024);
+ android::StringPool::FlattenUtf8(&buffer, pool, diag);
std::string* data = out_pb_pool->mutable_data();
data->reserve(buffer.size());
size_t offset = 0;
- for (const BigBuffer::Block& block : buffer) {
+ for (const android::BigBuffer::Block& block : buffer) {
data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
offset += block.size;
}
}
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
- StringPool::Ref ref = src_pool->MakeRef(source.path);
+void SerializeSourceToPb(const android::Source& source, android::StringPool* src_pool,
+ pb::Source* out_pb_source) {
+ android::StringPool::Ref ref = src_pool->MakeRef(source.path);
out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
if (source.line) {
out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
@@ -276,7 +278,7 @@ void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_
static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
std::vector<Overlayable*>& serialized_overlayables,
- StringPool* source_pool, pb::Entry* pb_entry,
+ android::StringPool* source_pool, pb::Entry* pb_entry,
pb::ResourceTable* pb_table) {
// Retrieve the index of the overlayable in the list of groups that have already been serialized.
size_t i;
@@ -337,8 +339,8 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item
}
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
- IDiagnostics* diag, SerializeTableOptions options) {
- auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>();
+ android::IDiagnostics* diag, SerializeTableOptions options) {
+ auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<android::StringPool>();
pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
pb_fingerprint->set_tool(util::GetToolName());
@@ -358,7 +360,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
if (type.id) {
pb_type->mutable_type_id()->set_id(type.id.value());
}
- pb_type->set_name(to_string(type.type).to_string());
+ pb_type->set_name(type.named_type.to_string());
// hardcoded string uses characters which make it an invalid resource name
static const char* obfuscated_resource_name = "0_resource_name_obfuscated";
@@ -367,7 +369,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
if (entry.id) {
pb_entry->mutable_entry_id()->set_id(entry.id.value());
}
- ResourceName resource_name({}, type.type, entry.name);
+ ResourceName resource_name({}, type.named_type, entry.name);
if (options.collapse_key_stringpool &&
options.name_collapse_exemptions.find(resource_name) ==
options.name_collapse_exemptions.end()) {
@@ -482,7 +484,7 @@ static void SerializeMacroToPb(const Macro& ref, pb::MacroBody* pb_macro) {
}
template <typename T>
-static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
+static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, android::StringPool* src_pool) {
if (src_pool != nullptr) {
SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
}
@@ -526,7 +528,7 @@ class ValueSerializer : public ConstValueVisitor {
public:
using ConstValueVisitor::Visit;
- ValueSerializer(pb::Value* out_value, StringPool* src_pool)
+ ValueSerializer(pb::Value* out_value, android::StringPool* src_pool)
: out_value_(out_value), src_pool_(src_pool) {
}
@@ -545,7 +547,7 @@ class ValueSerializer : public ConstValueVisitor {
void Visit(const StyledString* str) override {
pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
pb_str->set_value(str->value->value);
- for (const StringPool::Span& span : str->value->spans) {
+ for (const android::StringPool::Span& span : str->value->spans) {
pb::StyledString::Span* pb_span = pb_str->add_span();
pb_span->set_tag(*span.name);
pb_span->set_first_char(span.first_char);
@@ -693,12 +695,12 @@ class ValueSerializer : public ConstValueVisitor {
private:
pb::Value* out_value_;
- StringPool* src_pool_;
+ android::StringPool* src_pool_;
};
} // namespace
-void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
+void SerializeValueToPb(const Value& value, pb::Value* out_value, android::StringPool* src_pool) {
ValueSerializer serializer(out_value, src_pool);
value.Accept(&serializer);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
index b0d56307fbe4..b0a70d90f1b4 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -17,15 +17,14 @@
#ifndef AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
#define AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
-#include "StringPool.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/StringPool.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -51,7 +50,8 @@ struct SerializeTableOptions {
// Serializes a Value to its protobuf representation. An optional StringPool will hold the
// source path string.
-void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr);
+void SerializeValueToPb(const Value& value, pb::Value* out_value,
+ android::StringPool* src_pool = nullptr);
// Serialize an Item into its protobuf representation. pb::Item does not store the source path nor
// comments of an Item.
@@ -67,14 +67,15 @@ void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out
// Serializes a StringPool into its protobuf representation, which is really just the binary
// ResStringPool representation stuffed into a bytes field.
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag);
+void SerializeStringPoolToPb(const android::StringPool& pool, pb::StringPool* out_pb_pool,
+ android::IDiagnostics* diag);
// Serializes a ConfigDescription into its protobuf representation.
void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config);
// Serializes a ResourceTable into its protobuf representation.
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
- IDiagnostics* diag, SerializeTableOptions options = {});
+ android::IDiagnostics* diag, SerializeTableOptions options = {});
// Serializes a ResourceFile into its protobuf representation.
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index d1d72e012b31..692fa4247ae9 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -127,9 +127,9 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
context->GetDiagnostics()));
// Make a styled string.
- StyleString style_string;
+ android::StyleString style_string;
style_string.str = "hello";
- style_string.spans.push_back(Span{"b", 0u, 4u});
+ style_string.spans.push_back(android::Span{"b", 0u, 4u});
ASSERT_TRUE(table->AddResource(
NewResourceBuilder(test::ParseNameOrDie("com.app.a:string/styled"))
.SetValue(util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)))
@@ -164,8 +164,8 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
// Make an overlayable resource.
OverlayableItem overlayable_item(std::make_shared<Overlayable>(
- "OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)));
- overlayable_item.source = Source("res/values/overlayable.xml", 42);
+ "OverlayableName", "overlay://theme", android::Source("res/values/overlayable.xml", 40)));
+ overlayable_item.source = android::Source("res/values/overlayable.xml", 42);
ASSERT_TRUE(
table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:integer/overlayable"))
.SetOverlayable(overlayable_item)
@@ -271,7 +271,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
attr.compiled_value =
ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
- attr.compiled_value->SetSource(Source().WithLine(25));
+ attr.compiled_value->SetSource(android::Source().WithLine(25));
element.attributes.push_back(std::move(attr));
std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
@@ -292,7 +292,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
pb::XmlNode pb_xml;
SerializeXmlToPb(element, &pb_xml);
- StringPool pool;
+ android::StringPool pool;
xml::Element actual_el;
std::string error;
ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
@@ -365,7 +365,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXmlTrimEmptyWhitepsace) {
options.remove_empty_text_nodes = true;
SerializeXmlToPb(element, &pb_xml, options);
- StringPool pool;
+ android::StringPool pool;
xml::Element actual_el;
std::string error;
ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
@@ -898,7 +898,8 @@ TEST(ProtoSerializeTest, SerializeMacro) {
auto original = std::make_unique<Macro>();
original->raw_value = "\nThis being human is a guest house.";
original->style_string.str = " This being human is a guest house.";
- original->style_string.spans.emplace_back(Span{.name = "b", .first_char = 12, .last_char = 16});
+ original->style_string.spans.emplace_back(
+ android::Span{.name = "b", .first_char = 12, .last_char = 16});
original->untranslatable_sections.emplace_back(UntranslatableSection{.start = 12, .end = 17});
original->alias_namespaces.emplace_back(
Macro::Namespace{.alias = "prefix", .package_name = "package.name", .is_private = true});
@@ -951,4 +952,76 @@ TEST(ProtoSerializeTest, StagedId) {
EXPECT_THAT(result.value().entry->staged_id.value().id, Eq(ResourceId(0x01ff0001)));
}
+TEST(ProtoSerializeTest, CustomResourceTypes) {
+ const uint32_t id_one_id = 0x7f020000;
+ const uint32_t id_2_two_id = 0x7f030000;
+ const uint32_t integer_three_id = 0x7f030000;
+ const uint32_t integer_1_four_id = 0x7f030000;
+ const uint32_t layout_bar_id = 0x7f050000;
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/one", ResourceId(id_one_id))
+ .AddSimple("com.app.test:id.2/two", ResourceId(id_2_two_id))
+ .AddValue(
+ "com.app.test:integer/one", ResourceId(integer_three_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 10u))
+ .AddValue(
+ "com.app.test:integer.1/one", ResourceId(integer_1_four_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 1u))
+ .AddValue(
+ "com.app.test:integer.1/one", test::ParseConfigOrDie("v1"),
+ ResourceId(integer_1_four_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 2u))
+ .AddFileReference("com.app.test:layout.custom/bar", ResourceId(layout_bar_id),
+ "res/layout/bar.xml")
+ .Build();
+
+ test::TestFile file_a("res/layout/bar.xml");
+ MockFileCollection files;
+ EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml"))).WillRepeatedly(::testing::Return(&file_a));
+
+ ResourceTable new_table;
+ pb::ResourceTable pb_table;
+ std::string error;
+ SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+ DeserializeTableFromPb(pb_table, &files, &new_table, &error);
+ ASSERT_THAT(error, IsEmpty());
+
+ auto bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.test:integer.1/one", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("1")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer.1/one",
+ test::ParseConfigOrDie("v1"), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("2")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("10")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
+ test::ParseConfigOrDie("v1"), "");
+ ASSERT_THAT(bp, IsNull());
+
+ auto id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id/one",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(id, NotNull());
+
+ id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id.2/two",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(id, NotNull());
+
+ auto custom_layout = test::GetValueForConfigAndProduct<FileReference>(
+ &new_table, "com.app.test:layout.custom/bar", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(custom_layout, NotNull());
+ EXPECT_THAT(*(custom_layout->path), Eq("res/layout/bar.xml"));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/integration-tests/DumpTest/components.apk b/tools/aapt2/integration-tests/DumpTest/components.apk
new file mode 100644
index 000000000000..deb55ea6fda3
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected.txt b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
new file mode 100644
index 000000000000..79b6706e4a9f
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
@@ -0,0 +1,56 @@
+package: name='com.example.bundletool.minimal' versionCode='1' versionName='1.0' platformBuildVersionName='12' platformBuildVersionCode='31' compileSdkVersion='31' compileSdkVersionCodename='12'
+sdkVersion:'21'
+targetSdkVersion:'31'
+uses-configuration: reqTouchScreen='3' reqKeyboardType='2' reqHardKeyboard='-1' reqNavigation='3' reqFiveWayNav='-1'
+supports-gl-texture:'GL_OES_compressed_paletted_texture'
+uses-permission: name='android.permission.BIND_ACCESSIBILITY_SERVICE' maxSdkVersion='24'
+uses-permission-sdk-23: name='android.permission.RECEIVE_SMS'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
+compatible-screens:'500/240','400/160'
+application-label:'minimal'
+application-icon-160:'res/uF.xml'
+application-icon-240:'res/uF.xml'
+application-icon-320:'res/uF.xml'
+application-icon-480:'res/uF.xml'
+application-icon-640:'res/uF.xml'
+application-icon-65534:'res/uF.xml'
+application: label='minimal' icon='res/uF.xml'
+uses-library:'mylib1'
+uses-library-not-required:'my_optional_lib'
+uses-native-library:'native1'
+uses-native-library-not-required:'optional'
+launchable-activity: name='com.example.bundletool.minimal.MainActivity' label='minimal' icon=''
+meta-data: name='android.nfc.cardemulation.host_apdu_service' resource='res/dU.xml'
+uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.READ_EXTERNAL_STORAGE' reason='requested WRITE_EXTERNAL_STORAGE'
+feature-group: label=''
+ uses-feature: name='android.hardware.bluetooth'
+ uses-feature: name='android.hardware.camera'
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+ uses-feature-sdk-23: name='android.hardware.telephony'
+ uses-implied-feature-sdk-23: name='android.hardware.telephony' reason='requested a telephony permission'
+provides-component:'app-widget'
+provides-component:'device-admin'
+provides-component:'ime'
+provides-component:'wallpaper'
+provides-component:'accessibility'
+provides-component:'print-service'
+provides-component:'search'
+provides-component:'document-provider'
+provides-component:'notification-listener'
+provides-component:'dream'
+provides-component:'camera'
+provides-component:'camera-secure'
+main
+other-receivers
+other-services
+supports-screens: 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+requires-smallest-width:'240'
+compatible-width-limit:'360'
+largest-width-limit:'480'
+locales: '--_--'
+densities: '160' '240' '320' '480' '640' '65534'
+native-code: 'x86_64'
+alt-native-code: 'x86'
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
new file mode 100644
index 000000000000..775641054c06
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
@@ -0,0 +1,165 @@
+badging {
+ package {
+ package: "com.example.bundletool.minimal"
+ version_code: 1
+ version_name: "1.0"
+ platform_version_name: "12"
+ platform_version_code: "31"
+ compile_sdk_version: 31
+ compile_sdk_version_codename: "12"
+ }
+ application {
+ label: "minimal"
+ icon: "res/uF.xml"
+ density_icons {
+ key: 160
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 240
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 320
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 480
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 640
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 65534
+ value: "res/uF.xml"
+ }
+ }
+ uses_sdk {
+ min_sdk_version: 21
+ target_sdk_version: 31
+ }
+ uses_configuration {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
+ supports_screen {
+ screens: NORMAL
+ screens: LARGE
+ screens: XLARGE
+ supports_any_densities: true
+ requires_smallest_width_dp: 240
+ compatible_width_limit_dp: 360
+ largest_width_limit_dp: 480
+ }
+ launchable_activity {
+ name: "com.example.bundletool.minimal.MainActivity"
+ label: "minimal"
+ }
+ compatible_screens {
+ screens {
+ size: 500
+ density: 240
+ }
+ screens {
+ size: 400
+ density: 160
+ }
+ }
+ architectures {
+ architectures: "x86_64"
+ alt_architectures: "x86"
+ }
+ supports_gl_texture {
+ name: "GL_OES_compressed_paletted_texture"
+ }
+ components {
+ main: true
+ other_receivers: true
+ other_services: true
+ provided_components: "app-widget"
+ provided_components: "device-admin"
+ provided_components: "ime"
+ provided_components: "wallpaper"
+ provided_components: "accessibility"
+ provided_components: "print-service"
+ provided_components: "search"
+ provided_components: "document-provider"
+ provided_components: "notification-listener"
+ provided_components: "dream"
+ provided_components: "camera"
+ provided_components: "camera-secure"
+ }
+ densities: 160
+ densities: 240
+ densities: 320
+ densities: 480
+ densities: 640
+ densities: 65534
+ feature_groups {
+ features {
+ name: "android.hardware.bluetooth"
+ required: true
+ }
+ features {
+ name: "android.hardware.camera"
+ required: true
+ }
+ features {
+ name: "android.hardware.faketouch"
+ implied_data {
+ reasons: "default feature for all apps"
+ }
+ }
+ features {
+ name: "android.hardware.telephony"
+ implied_data {
+ from_sdk_23_permission: true
+ reasons: "requested a telephony permission"
+ }
+ }
+ }
+ uses_permissions {
+ name: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ max_sdk_version: 24
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.RECEIVE_SMS"
+ sdk23_and_above: true
+ }
+ uses_permissions {
+ name: "android.permission.WRITE_EXTERNAL_STORAGE"
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.READ_EXTERNAL_STORAGE"
+ required: true
+ implied: true
+ }
+ permissions {
+ name: "minimal.FIRST_PERMISSION"
+ }
+ uses_libraries {
+ name: "mylib1"
+ required: true
+ }
+ uses_libraries {
+ name: "my_optional_lib"
+ }
+ uses_native_libraries {
+ name: "native1"
+ required: true
+ }
+ uses_native_libraries {
+ name: "optional"
+ }
+ metadata {
+ name: "android.nfc.cardemulation.host_apdu_service"
+ resource_string: "res/dU.xml"
+ }
+}
diff --git a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
new file mode 100644
index 000000000000..bd7673616ddc
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
@@ -0,0 +1,2310 @@
+badging {
+ package {
+ package: "com.example.bundletool.minimal"
+ version_code: 1
+ version_name: "1.0"
+ platform_version_name: "12"
+ platform_version_code: "31"
+ compile_sdk_version: 31
+ compile_sdk_version_codename: "12"
+ }
+ application {
+ label: "minimal"
+ icon: "res/uF.xml"
+ density_icons {
+ key: 160
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 240
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 320
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 480
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 640
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 65534
+ value: "res/uF.xml"
+ }
+ }
+ uses_sdk {
+ min_sdk_version: 21
+ target_sdk_version: 31
+ }
+ uses_configuration {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
+ supports_screen {
+ screens: NORMAL
+ screens: LARGE
+ screens: XLARGE
+ supports_any_densities: true
+ requires_smallest_width_dp: 240
+ compatible_width_limit_dp: 360
+ largest_width_limit_dp: 480
+ }
+ launchable_activity {
+ name: "com.example.bundletool.minimal.MainActivity"
+ label: "minimal"
+ }
+ compatible_screens {
+ screens {
+ size: 500
+ density: 240
+ }
+ screens {
+ size: 400
+ density: 160
+ }
+ }
+ architectures {
+ architectures: "x86_64"
+ alt_architectures: "x86"
+ }
+ supports_gl_texture {
+ name: "GL_OES_compressed_paletted_texture"
+ }
+ components {
+ main: true
+ other_receivers: true
+ other_services: true
+ provided_components: "app-widget"
+ provided_components: "device-admin"
+ provided_components: "ime"
+ provided_components: "wallpaper"
+ provided_components: "accessibility"
+ provided_components: "print-service"
+ provided_components: "search"
+ provided_components: "document-provider"
+ provided_components: "notification-listener"
+ provided_components: "dream"
+ provided_components: "camera"
+ provided_components: "camera-secure"
+ }
+ densities: 160
+ densities: 240
+ densities: 320
+ densities: 480
+ densities: 640
+ densities: 65534
+ feature_groups {
+ features {
+ name: "android.hardware.bluetooth"
+ required: true
+ }
+ features {
+ name: "android.hardware.camera"
+ required: true
+ }
+ features {
+ name: "android.hardware.faketouch"
+ implied_data {
+ reasons: "default feature for all apps"
+ }
+ }
+ features {
+ name: "android.hardware.telephony"
+ implied_data {
+ from_sdk_23_permission: true
+ reasons: "requested a telephony permission"
+ }
+ }
+ }
+ uses_permissions {
+ name: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ max_sdk_version: 24
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.RECEIVE_SMS"
+ sdk23_and_above: true
+ }
+ uses_permissions {
+ name: "android.permission.WRITE_EXTERNAL_STORAGE"
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.READ_EXTERNAL_STORAGE"
+ required: true
+ implied: true
+ }
+ permissions {
+ name: "minimal.FIRST_PERMISSION"
+ }
+ uses_libraries {
+ name: "mylib1"
+ required: true
+ }
+ uses_libraries {
+ name: "my_optional_lib"
+ }
+ uses_native_libraries {
+ name: "native1"
+ required: true
+ }
+ uses_native_libraries {
+ name: "optional"
+ }
+ metadata {
+ name: "android.nfc.cardemulation.host_apdu_service"
+ resource_string: "res/dU.xml"
+ }
+}
+resource_table {
+ source_pool {
+ data: "\001\000\034\000$\000\000\000\001\000\000\000\000\000\000\000\000\001\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ }
+ package {
+ package_id {
+ id: 127
+ }
+ package_name: "com.example.bundletool.minimal"
+ type {
+ type_id {
+ id: 1
+ }
+ name: "color"
+ entry {
+ entry_id {
+ }
+ name: "black"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278190080
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "purple_200"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4290479868
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "purple_500"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4284612846
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 3
+ }
+ name: "purple_700"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4281794739
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 4
+ }
+ name: "teal_200"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278442693
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 5
+ }
+ name: "teal_700"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278290310
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 6
+ }
+ name: "white"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4294967295
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 2
+ }
+ name: "dimen"
+ entry {
+ entry_id {
+ }
+ name: "fab_margin"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ dimension_value: 4097
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 3
+ }
+ name: "drawable"
+ entry {
+ entry_id {
+ }
+ name: "$ic_launcher_foreground__0"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 24
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/Za.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "ic_launcher_background"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/3N.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "ic_launcher_foreground"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 24
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/qm.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 4
+ }
+ name: "mipmap"
+ entry {
+ entry_id {
+ }
+ name: "ic_launcher"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 160
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/u3.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 240
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/SD.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 320
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/jy.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 480
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/D2.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 640
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/CG.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 26
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/uF.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "ic_launcher_round"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 160
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/7c.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 240
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/tf.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 320
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/1S.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 480
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/5Q.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 640
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/C9.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 26
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/oy.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 5
+ }
+ name: "string"
+ entry {
+ entry_id {
+ }
+ name: "action_settings"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Settings"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "app_name"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "minimal"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "first_fragment_label"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "First Fragment"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 3
+ }
+ name: "hello_first_fragment"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Hello first fragment"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 4
+ }
+ name: "hello_second_fragment"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Hello second fragment. Arg: %1$s"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 5
+ }
+ name: "next"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Next"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 6
+ }
+ name: "previous"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Previous"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 7
+ }
+ name: "second_fragment_label"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Second Fragment"
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 6
+ }
+ name: "xml"
+ entry {
+ entry_id {
+ }
+ name: "apduservice"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/dU.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ tool_fingerprint {
+ tool: "Android Asset Packaging Tool (aapt)"
+ version: "2.19-SOONG BUILD NUMBER PLACEHOLDER"
+ }
+}
+xml_files {
+ path: "res/oy.xml"
+ root {
+ element {
+ namespace_declaration {
+ prefix: "android"
+ uri: "http://schemas.android.com/apk/res/android"
+ source {
+ line_number: 2
+ }
+ }
+ name: "adaptive-icon"
+ child {
+ element {
+ name: "background"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "drawable"
+ source {
+ }
+ resource_id: 16843161
+ compiled_item {
+ ref {
+ id: 2130903041
+ }
+ }
+ }
+ }
+ source {
+ line_number: 3
+ }
+ }
+ child {
+ element {
+ name: "foreground"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "drawable"
+ source {
+ }
+ resource_id: 16843161
+ compiled_item {
+ ref {
+ id: 2130903042
+ }
+ }
+ }
+ }
+ source {
+ line_number: 4
+ }
+ }
+ }
+ source {
+ line_number: 2
+ }
+ }
+}
+xml_files {
+ path: "AndroidManifest.xml"
+ root {
+ element {
+ namespace_declaration {
+ prefix: "android"
+ uri: "http://schemas.android.com/apk/res/android"
+ source {
+ line_number: 2
+ }
+ }
+ name: "manifest"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "versionCode"
+ source {
+ }
+ resource_id: 16843291
+ compiled_item {
+ prim {
+ int_decimal_value: 1
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "versionName"
+ value: "1.0"
+ resource_id: 16843292
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compileSdkVersion"
+ source {
+ }
+ resource_id: 16844146
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compileSdkVersionCodename"
+ value: "12"
+ resource_id: 16844147
+ }
+ attribute {
+ name: "package"
+ value: "com.example.bundletool.minimal"
+ }
+ attribute {
+ name: "platformBuildVersionCode"
+ source {
+ }
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ attribute {
+ name: "platformBuildVersionName"
+ source {
+ }
+ compiled_item {
+ prim {
+ int_decimal_value: 12
+ }
+ }
+ }
+ child {
+ element {
+ name: "uses-sdk"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "minSdkVersion"
+ source {
+ }
+ resource_id: 16843276
+ compiled_item {
+ prim {
+ int_decimal_value: 21
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "targetSdkVersion"
+ source {
+ }
+ resource_id: 16843376
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ }
+ source {
+ line_number: 7
+ }
+ }
+ child {
+ element {
+ name: "supports-screens"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "anyDensity"
+ source {
+ }
+ resource_id: 16843372
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "smallScreens"
+ source {
+ }
+ resource_id: 16843396
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "normalScreens"
+ source {
+ }
+ resource_id: 16843397
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "largeScreens"
+ source {
+ }
+ resource_id: 16843398
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "requiresSmallestWidthDp"
+ source {
+ }
+ resource_id: 16843620
+ compiled_item {
+ prim {
+ int_decimal_value: 240
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compatibleWidthLimitDp"
+ source {
+ }
+ resource_id: 16843621
+ compiled_item {
+ prim {
+ int_decimal_value: 360
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "largestWidthLimitDp"
+ source {
+ }
+ resource_id: 16843622
+ compiled_item {
+ prim {
+ int_decimal_value: 480
+ }
+ }
+ }
+ }
+ source {
+ line_number: 11
+ }
+ }
+ child {
+ element {
+ name: "uses-configuration"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqTouchScreen"
+ source {
+ }
+ resource_id: 16843303
+ compiled_item {
+ prim {
+ int_decimal_value: 3
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqKeyboardType"
+ source {
+ }
+ resource_id: 16843304
+ compiled_item {
+ prim {
+ int_decimal_value: 2
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqHardKeyboard"
+ source {
+ }
+ resource_id: 16843305
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqNavigation"
+ source {
+ }
+ resource_id: 16843306
+ compiled_item {
+ prim {
+ int_decimal_value: 3
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqFiveWayNav"
+ source {
+ }
+ resource_id: 16843314
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 20
+ }
+ }
+ child {
+ element {
+ name: "supports-gl-texture"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "GL_OES_compressed_paletted_texture"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 27
+ }
+ }
+ child {
+ element {
+ name: "permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "minimal.FIRST_PERMISSION"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 29
+ }
+ }
+ child {
+ element {
+ name: "uses-feature"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.hardware.camera"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 31
+ }
+ }
+ child {
+ element {
+ name: "uses-feature"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.hardware.bluetooth"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 32
+ }
+ }
+ child {
+ element {
+ name: "uses-permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "maxSdkVersion"
+ source {
+ }
+ resource_id: 16843377
+ compiled_item {
+ prim {
+ int_decimal_value: 24
+ }
+ }
+ }
+ }
+ source {
+ line_number: 34
+ }
+ }
+ child {
+ element {
+ name: "uses-permission-sdk-23"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.RECEIVE_SMS"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 38
+ }
+ }
+ child {
+ element {
+ name: "uses-permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.WRITE_EXTERNAL_STORAGE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 40
+ }
+ }
+ child {
+ element {
+ name: "compatible-screens"
+ child {
+ element {
+ name: "screen"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenSize"
+ source {
+ }
+ resource_id: 16843466
+ compiled_item {
+ prim {
+ int_decimal_value: 500
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenDensity"
+ source {
+ }
+ resource_id: 16843467
+ compiled_item {
+ prim {
+ int_decimal_value: 240
+ }
+ }
+ }
+ }
+ source {
+ line_number: 43
+ }
+ }
+ child {
+ element {
+ name: "screen"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenSize"
+ source {
+ }
+ resource_id: 16843466
+ compiled_item {
+ prim {
+ int_decimal_value: 400
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenDensity"
+ source {
+ }
+ resource_id: 16843467
+ compiled_item {
+ prim {
+ int_decimal_value: 160
+ }
+ }
+ }
+ }
+ source {
+ line_number: 46
+ }
+ }
+ }
+ source {
+ line_number: 42
+ }
+ }
+ child {
+ element {
+ name: "application"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "icon"
+ source {
+ }
+ resource_id: 16842754
+ compiled_item {
+ ref {
+ id: 2130968576
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "allowBackup"
+ source {
+ }
+ resource_id: 16843392
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "supportsRtl"
+ source {
+ }
+ resource_id: 16843695
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "multiArch"
+ source {
+ }
+ resource_id: 16843918
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "roundIcon"
+ source {
+ }
+ resource_id: 16844076
+ compiled_item {
+ ref {
+ id: 2130968577
+ }
+ }
+ }
+ child {
+ element {
+ name: "uses-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "mylib1"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 58
+ }
+ }
+ child {
+ element {
+ name: "uses-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "my_optional_lib"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ }
+ source {
+ line_number: 61
+ }
+ }
+ child {
+ element {
+ name: "uses-native-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "native1"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 65
+ }
+ }
+ child {
+ element {
+ name: "uses-native-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "optional"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ }
+ source {
+ line_number: 68
+ }
+ }
+ child {
+ element {
+ name: "activity"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.MainActivity"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.MAIN"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 77
+ }
+ }
+ child {
+ element {
+ name: "category"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.category.LAUNCHER"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 79
+ }
+ }
+ }
+ source {
+ line_number: 76
+ }
+ }
+ }
+ source {
+ line_number: 72
+ }
+ }
+ child {
+ element {
+ name: "activity"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.AnotherActivity"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.VIDEO_CAMERA"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 87
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.STILL_IMAGE_CAMERA_SECURE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 88
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.SEARCH"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 89
+ }
+ }
+ }
+ source {
+ line_number: 86
+ }
+ }
+ }
+ source {
+ line_number: 82
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneReceiver"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.appwidget.action.APPWIDGET_UPDATE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 97
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.app.action.DEVICE_ADMIN_ENABLED"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 98
+ }
+ }
+ }
+ source {
+ line_number: 96
+ }
+ }
+ }
+ source {
+ line_number: 93
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.TwoReceiver"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_DEVICE_ADMIN"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.app.action.DEVICE_ADMIN_ENABLED"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 106
+ }
+ }
+ }
+ source {
+ line_number: 105
+ }
+ }
+ }
+ source {
+ line_number: 101
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.ThreeReceiver"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 109
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.view.InputMethod"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 115
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.wallpaper.WallpaperService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 116
+ }
+ }
+ }
+ source {
+ line_number: 114
+ }
+ }
+ }
+ source {
+ line_number: 111
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$TwoService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.accessibilityservice.AccessibilityService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 124
+ }
+ }
+ }
+ source {
+ line_number: 123
+ }
+ }
+ }
+ source {
+ line_number: 119
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$ThreeService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_PRINT_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.printservice.PrintService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 132
+ }
+ }
+ }
+ source {
+ line_number: 131
+ }
+ }
+ }
+ source {
+ line_number: 127
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$FourService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_NFC_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.nfc.cardemulation.action.HOST_APDU_SERVICE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 140
+ }
+ }
+ }
+ source {
+ line_number: 139
+ }
+ }
+ child {
+ element {
+ name: "meta-data"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.nfc.cardemulation.host_apdu_service"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "resource"
+ source {
+ }
+ resource_id: 16842789
+ compiled_item {
+ ref {
+ id: 2131099648
+ }
+ }
+ }
+ }
+ source {
+ line_number: 143
+ }
+ }
+ }
+ source {
+ line_number: 135
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$FiveService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.notification.NotificationListenerService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 152
+ }
+ }
+ }
+ source {
+ line_number: 151
+ }
+ }
+ }
+ source {
+ line_number: 147
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$SixService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_DREAM_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.dreams.DreamService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 160
+ }
+ }
+ }
+ source {
+ line_number: 159
+ }
+ }
+ }
+ source {
+ line_number: 155
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$SevenService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 163
+ }
+ }
+ child {
+ element {
+ name: "provider"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneProvider"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.MANAGE_DOCUMENTS"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "authorities"
+ value: "A"
+ resource_id: 16842776
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "grantUriPermissions"
+ source {
+ }
+ resource_id: 16842779
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.content.action.DOCUMENTS_PROVIDER"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 172
+ }
+ }
+ }
+ source {
+ line_number: 171
+ }
+ }
+ }
+ source {
+ line_number: 165
+ }
+ }
+ }
+ source {
+ line_number: 51
+ }
+ }
+ }
+ source {
+ line_number: 2
+ }
+ }
+}
diff --git a/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt b/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt
new file mode 100644
index 000000000000..f79de5cba11d
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt
@@ -0,0 +1,5 @@
+package: com.example.bundletool.minimal
+permission: minimal.FIRST_PERMISSION
+uses-permission: name='android.permission.BIND_ACCESSIBILITY_SERVICE' maxSdkVersion='24'
+uses-permission-sdk-23: name='android.permission.RECEIVE_SMS'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
diff --git a/tools/aapt2/integration-tests/DumpTest/minimal.apk b/tools/aapt2/integration-tests/DumpTest/minimal.apk
new file mode 100644
index 000000000000..a8415faca390
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/minimal.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt b/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt
new file mode 100644
index 000000000000..85ab5d80cd39
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt
@@ -0,0 +1,92 @@
+package: name='com.lato.bubblegirl' versionCode='33' versionName='1.0.0' platformBuildVersionName='8.1.0' platformBuildVersionCode='27'
+sdkVersion:'19'
+targetSdkVersion:'26'
+application-label:'Bubble Girl'
+application-label-ar:'Bubble Girl'
+application-label-az:'Bubble Girl'
+application-label-be:'Bubble Girl'
+application-label-bg:'Bubble Girl'
+application-label-bn:'Bubble Girl'
+application-label-bs:'Bubble Girl'
+application-label-ca:'Bubble Girl'
+application-label-cs:'Bubble Girl'
+application-label-da:'Bubble Girl'
+application-label-de:'Bubble Girl'
+application-label-el:'Bubble Girl'
+application-label-es:'Bubble Girl'
+application-label-es-ES:'Bubble Girl'
+application-label-et:'Bubble Girl'
+application-label-eu:'Bubble Girl'
+application-label-fa:'Bubble Girl'
+application-label-fi:'Bubble Girl'
+application-label-fr:'Bubble Girl'
+application-label-fr-CA:'Bubble Girl'
+application-label-gl:'Bubble Girl'
+application-label-hi:'Bubble Girl'
+application-label-hr:'Bubble Girl'
+application-label-hu:'Bubble Girl'
+application-label-hy:'Bubble Girl'
+application-label-in:'Bubble Girl'
+application-label-is:'Bubble Girl'
+application-label-it:'Bubble Girl'
+application-label-iw:'Bubble Girl'
+application-label-ja:'Bubble Girl'
+application-label-jv:'Bubble Girl'
+application-label-ka:'Bubble Girl'
+application-label-kk:'Bubble Girl'
+application-label-kn:'Bubble Girl'
+application-label-ko:'Bubble Girl'
+application-label-lt:'Bubble Girl'
+application-label-lv:'Bubble Girl'
+application-label-mk:'Bubble Girl'
+application-label-ml:'Bubble Girl'
+application-label-mr:'Bubble Girl'
+application-label-ms:'Bubble Girl'
+application-label-nb:'Bubble Girl'
+application-label-nl:'Bubble Girl'
+application-label-pa:'Bubble Girl'
+application-label-pl:'Bubble Girl'
+application-label-pt-BR:'Bubble Girl'
+application-label-pt-PT:'Bubble Girl'
+application-label-ro:'Bubble Girl'
+application-label-ru:'Bubble Girl'
+application-label-sk:'Bubble Girl'
+application-label-sl:'Bubble Girl'
+application-label-sq:'Bubble Girl'
+application-label-sr:'Bubble Girl'
+application-label-su:'Bubble Girl'
+application-label-sv:'Bubble Girl'
+application-label-ta:'Bubble Girl'
+application-label-te:'Bubble Girl'
+application-label-th:'Bubble Girl'
+application-label-tl:'Bubble Girl'
+application-label-tr:'Bubble Girl'
+application-label-tt:'Bubble Girl'
+application-label-uk:'Bubble Girl'
+application-label-vi:'Bubble Girl'
+application-label-zh-CN:'Bubble Girl'
+application-label-zh-HK:'Bubble Girl'
+application-label-zh-TW:'Bubble Girl'
+application-icon-160:'res/theme/1f.png'
+application-icon-240:'res/theme/1f.png'
+application-icon-320:'res/theme/1f.png'
+application-icon-480:'res/theme/1f.png'
+application-icon-640:'res/theme/1f.png'
+application: label='Bubble Girl' icon='res/theme/1f.png'
+launchable-activity: name='com.sonymobile.runtimeskinning.livewallpaperlib.configactivity.LauncherActivity' label='' icon=''
+uses-library:'com.sony.device'
+uses-permission: name='com.sonymobile.permission.RUNTIME_SKIN'
+feature-group: label=''
+ uses-gl-es: '0x30000'
+ uses-feature: name='android.software.live_wallpaper'
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+ uses-feature: name='android.hardware.screen.portrait'
+ uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
+provides-component:'wallpaper'
+main
+other-activities
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales: '--_--' 'ar' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'el' 'es' 'es-ES' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'hi' 'hr' 'hu' 'hy' 'in' 'is' 'it' 'iw' 'ja' 'jv' 'ka' 'kk' 'kn' 'ko' 'lt' 'lv' 'mk' 'ml' 'mr' 'ms' 'nb' 'nl' 'pa' 'pl' 'pt-BR' 'pt-PT' 'ro' 'ru' 'sk' 'sl' 'sq' 'sr' 'su' 'sv' 'ta' 'te' 'th' 'tl' 'tr' 'tt' 'uk' 'vi' 'zh-CN' 'zh-HK' 'zh-TW'
+densities: '160' '240' '320' '480' '640'
diff --git a/tools/aapt2/io/BigBufferStream.h b/tools/aapt2/io/BigBufferStream.h
index 8b5c8b84cd3c..63a5e5756ed4 100644
--- a/tools/aapt2/io/BigBufferStream.h
+++ b/tools/aapt2/io/BigBufferStream.h
@@ -17,15 +17,15 @@
#ifndef AAPT_IO_BIGBUFFERSTREAM_H
#define AAPT_IO_BIGBUFFERSTREAM_H
+#include "androidfw/BigBuffer.h"
#include "io/Io.h"
-#include "util/BigBuffer.h"
namespace aapt {
namespace io {
class BigBufferInputStream : public KnownSizeInputStream {
public:
- inline explicit BigBufferInputStream(const BigBuffer* buffer)
+ inline explicit BigBufferInputStream(const android::BigBuffer* buffer)
: buffer_(buffer), iter_(buffer->begin()) {
}
virtual ~BigBufferInputStream() = default;
@@ -47,15 +47,15 @@ class BigBufferInputStream : public KnownSizeInputStream {
private:
DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
- const BigBuffer* buffer_;
- BigBuffer::const_iterator iter_;
+ const android::BigBuffer* buffer_;
+ android::BigBuffer::const_iterator iter_;
size_t offset_ = 0;
size_t bytes_read_ = 0;
};
class BigBufferOutputStream : public OutputStream {
public:
- inline explicit BigBufferOutputStream(BigBuffer* buffer) : buffer_(buffer) {
+ inline explicit BigBufferOutputStream(android::BigBuffer* buffer) : buffer_(buffer) {
}
virtual ~BigBufferOutputStream() = default;
@@ -70,7 +70,7 @@ class BigBufferOutputStream : public OutputStream {
private:
DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
};
} // namespace io
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 565aad6f2284..422658a0309e 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -22,8 +22,7 @@
#include <vector>
#include "android-base/macros.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "io/Data.h"
#include "util/Files.h"
#include "util/Util.h"
@@ -49,7 +48,7 @@ class IFile {
// Returns the source of this file. This is for presentation to the user and
// may not be a valid file system path (for example, it may contain a '@' sign to separate
// the files within a ZIP archive from the path to the containing ZIP archive.
- virtual const Source& GetSource() const = 0;
+ virtual const android::Source& GetSource() const = 0;
IFile* CreateFileSegment(size_t offset, size_t len);
@@ -76,7 +75,7 @@ class FileSegment : public IFile {
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override {
+ const android::Source& GetSource() const override {
return file_->GetSource();
}
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index fc2e45e74b4d..3f071af08844 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -19,13 +19,12 @@
#include <dirent.h>
#include "android-base/errors.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
-#include "utils/FileMap.h"
-#include "Source.h"
#include "io/FileStream.h"
#include "util/Files.h"
-
#include "util/Util.h"
+#include "utils/FileMap.h"
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
@@ -33,7 +32,8 @@ using ::android::base::SystemErrorCodeToString;
namespace aapt {
namespace io {
-RegularFile::RegularFile(const Source& source) : source_(source) {}
+RegularFile::RegularFile(const android::Source& source) : source_(source) {
+}
std::unique_ptr<IData> RegularFile::OpenAsData() {
android::FileMap map;
@@ -50,7 +50,7 @@ std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() {
return util::make_unique<FileInputStream>(source_.path);
}
-const Source& RegularFile::GetSource() const {
+const android::Source& RegularFile::GetSource() const {
return source_;
}
@@ -118,7 +118,7 @@ std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiec
}
IFile* FileCollection::InsertFile(const StringPiece& path) {
- return (files_[path.to_string()] = util::make_unique<RegularFile>(Source(path))).get();
+ return (files_[path.to_string()] = util::make_unique<RegularFile>(android::Source(path))).get();
}
IFile* FileCollection::FindFile(const StringPiece& path) {
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 04c6fa15bc85..bc03b9b4391e 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -27,16 +27,16 @@ namespace io {
// A regular file from the file system. Uses mmap to open the data.
class RegularFile : public IFile {
public:
- explicit RegularFile(const Source& source);
+ explicit RegularFile(const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override;
+ const android::Source& GetSource() const override;
private:
DISALLOW_COPY_AND_ASSIGN(RegularFile);
- Source source_;
+ android::Source source_;
};
class FileCollection;
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index bb925c9b3f8e..afe54d408361 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -30,12 +30,14 @@ bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std:
uint32_t compression_flags, IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "writing " << out_path << " to archive");
}
if (!writer->WriteFile(out_path, compression_flags, in)) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive: " << writer->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
return false;
}
return true;
@@ -46,7 +48,8 @@ bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string
TRACE_CALL();
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "failed to open file");
return false;
}
return CopyInputStreamToArchive(context, data.get(), out_path, compression_flags, writer);
@@ -63,7 +66,8 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot
IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "writing " << out_path << " to archive");
}
if (writer->StartEntry(out_path, compression_flags)) {
@@ -72,8 +76,8 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot
// Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
::google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
if (!proto_msg->SerializeToZeroCopyStream(&adaptor)) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to write " << out_path << " to archive");
return false;
}
}
@@ -82,8 +86,8 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot
return true;
}
}
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive: " << writer->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage() << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
return false;
}
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 4380586b1d3c..400269c41230 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -16,22 +16,21 @@
#include "io/ZipArchive.h"
-#include "utils/FileMap.h"
-#include "ziparchive/zip_archive.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "trace/TraceBuffer.h"
#include "util/Files.h"
#include "util/Util.h"
+#include "utils/FileMap.h"
+#include "ziparchive/zip_archive.h"
using ::android::StringPiece;
namespace aapt {
namespace io {
-ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry,
- const Source& source)
- : zip_handle_(handle), zip_entry_(entry), source_(source) {}
+ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const android::Source& source)
+ : zip_handle_(handle), zip_entry_(entry), source_(source) {
+}
std::unique_ptr<IData> ZipFile::OpenAsData() {
// The file will fail to be mmaped if it is empty
@@ -68,7 +67,7 @@ std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
return OpenAsData();
}
-const Source& ZipFile::GetSource() const {
+const android::Source& ZipFile::GetSource() const {
return source_;
}
@@ -131,8 +130,8 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
continue;
}
- std::unique_ptr<IFile> file = util::make_unique<ZipFile>(collection->handle_, zip_data,
- Source(zip_entry_path, path.to_string()));
+ std::unique_ptr<IFile> file = util::make_unique<ZipFile>(
+ collection->handle_, zip_data, android::Source(zip_entry_path, path.to_string()));
collection->files_by_name_[zip_entry_path] = file.get();
collection->files_.push_back(std::move(file));
}
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index b283e57d4011..78c9c211ab57 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -32,17 +32,17 @@ namespace io {
// and copied into memory when opened. Otherwise it is mmapped from the ZIP archive.
class ZipFile : public IFile {
public:
- ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const Source& source);
+ ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override;
+ const android::Source& GetSource() const override;
bool WasCompressed() override;
private:
::ZipArchiveHandle zip_handle_;
::ZipEntry zip_entry_;
- Source source_;
+ android::Source source_;
};
class ZipFileCollection;
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index a963d9893f2f..a25ca22c288d 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -548,10 +548,11 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
}
// We need to make sure we hide the fact that we are generating kAttrPrivate attributes.
- const ResourceNameRef resource_name(
- package_name_to_generate,
- type.type == ResourceType::kAttrPrivate ? ResourceType::kAttr : type.type,
- unmangled_name.value());
+ const auto target_type = type.named_type.type == ResourceType::kAttrPrivate
+ ? ResourceNamedTypeWithDefaultName(ResourceType::kAttr)
+ : type.named_type;
+ const ResourceNameRef resource_name(package_name_to_generate, target_type,
+ unmangled_name.value());
// Check to see if the unmangled name is a valid Java name (not a keyword).
if (!IsValidSymbol(unmangled_name.value())) {
@@ -616,7 +617,8 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
for (const auto& package : table_->packages) {
for (const auto& type : package->types) {
- if (type->type == ResourceType::kAttrPrivate || type->type == ResourceType::kMacro) {
+ if (type->named_type.type == ResourceType::kAttrPrivate ||
+ type->named_type.type == ResourceType::kMacro) {
// We generate kAttrPrivate as part of the kAttr type, so skip them here.
// Macros are not actual resources, so skip them as well.
continue;
@@ -628,7 +630,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
std::unique_ptr<ClassDefinition> class_def;
if (out != nullptr) {
class_def = util::make_unique<ClassDefinition>(
- to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ to_string(type->named_type.type), ClassQualifier::kStatic, force_creation_if_empty);
}
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
@@ -636,9 +638,10 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
return false;
}
- if (type->type == ResourceType::kAttr) {
+ if (type->named_type.type == ResourceType::kAttr) {
// Also include private attributes in this same class.
- if (const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate)) {
+ if (const ResourceTableType* priv_type =
+ package->FindTypeWithDefaultName(ResourceType::kAttrPrivate)) {
if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
rewrite_method.get(), r_txt_printer.get())) {
return false;
@@ -646,7 +649,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
}
}
- if (out != nullptr && type->type == ResourceType::kStyleable && is_public) {
+ if (out != nullptr && type->named_type.type == ResourceType::kStyleable && is_public) {
// When generating a public R class, we don't want Styleable to be part
// of the API. It is only emitted for documentation purposes.
class_def->GetCommentBuilder()->AppendComment("@doconly");
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a0db41baecb4..65b63b7c0c61 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -18,7 +18,7 @@
#include <algorithm>
-#include "Source.h"
+#include "androidfw/Source.h"
#include "java/ClassDefinition.h"
#include "java/JavaClassGenerator.h"
#include "text/Unicode.h"
@@ -28,7 +28,8 @@ using ::aapt::text::IsJavaIdentifier;
namespace aapt {
-static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
+static std::optional<std::string> ExtractJavaIdentifier(android::IDiagnostics* diag,
+ const android::Source& source,
const std::string& value) {
std::string result = value;
size_t pos = value.rfind('.');
@@ -42,22 +43,22 @@ static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, cons
}
if (result.empty()) {
- diag->Error(DiagMessage(source) << "empty symbol");
+ diag->Error(android::DiagMessage(source) << "empty symbol");
return {};
}
if (!IsJavaIdentifier(result)) {
- diag->Error(DiagMessage(source) << "invalid Java identifier '" << result << "'");
+ diag->Error(android::DiagMessage(source) << "invalid Java identifier '" << result << "'");
return {};
}
return result;
}
-static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
- ClassDefinition* class_def) {
+static bool WriteSymbol(const android::Source& source, android::IDiagnostics* diag,
+ xml::Element* el, ClassDefinition* class_def) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (!attr) {
- diag->Error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
+ diag->Error(android::DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
return false;
}
@@ -72,21 +73,22 @@ static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element*
string_member->GetCommentBuilder()->AppendComment(el->comment);
if (class_def->AddMember(std::move(string_member)) == ClassDefinition::Result::kOverridden) {
- diag->Warn(DiagMessage(source.WithLine(el->line_number))
+ diag->Warn(android::DiagMessage(source.WithLine(el->line_number))
<< "duplicate definitions of '" << result.value() << "', overriding previous");
}
return true;
}
-std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
+std::unique_ptr<ClassDefinition> GenerateManifestClass(android::IDiagnostics* diag,
+ xml::XmlResource* res) {
xml::Element* el = xml::FindRootElement(res->root.get());
if (!el) {
- diag->Error(DiagMessage(res->file.source) << "no root tag defined");
+ diag->Error(android::DiagMessage(res->file.source) << "no root tag defined");
return {};
}
if (el->name != "manifest" && !el->namespace_uri.empty()) {
- diag->Error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
+ diag->Error(android::DiagMessage(res->file.source) << "no <manifest> root tag defined");
return {};
}
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 3f6645facaa2..3a45ef6d5ecc 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -17,13 +17,14 @@
#ifndef AAPT_JAVA_MANIFESTCLASSGENERATOR_H
#define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
#include "java/ClassDefinition.h"
#include "xml/XmlDom.h"
namespace aapt {
-std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
+std::unique_ptr<ClassDefinition> GenerateManifestClass(android::IDiagnostics* diag,
+ xml::XmlResource* res);
} // namespace aapt
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index e53e22070b62..80a46d553960 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -517,7 +517,7 @@ bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table
for (auto& type : pkg->types) {
for (auto& entry : type->entries) {
for (auto& config_value : entry->values) {
- ResourceName from(pkg->name, type->type, entry->name);
+ ResourceName from(pkg->name, type->named_type, entry->name);
ReferenceVisitor visitor(context, from, keep_set);
config_value->value->Accept(&visitor);
}
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index a01b64d024d2..267f7ede274a 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -22,12 +22,11 @@
#include <set>
#include <string>
-#include "androidfw/StringPiece.h"
-
#include "Resource.h"
#include "ResourceTable.h"
-#include "Source.h"
#include "ValueVisitor.h"
+#include "androidfw/Source.h"
+#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
@@ -37,7 +36,7 @@ namespace proguard {
struct UsageLocation {
ResourceName name;
- Source source;
+ android::Source source;
};
struct NameAndSignature {
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index 328ac97090a8..3dbd7e613a3e 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -75,7 +75,7 @@ bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) {
CloningValueTransformer cloner(&table->string_pool);
for (auto& package : table->packages) {
for (auto& type : package->types) {
- if (type->type != ResourceType::kStyle) {
+ if (type->named_type.type != ResourceType::kStyle) {
continue;
}
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index be6c930b9284..44cd276f77a2 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -101,9 +101,10 @@ class ProductFilter : public IResourceTableConsumer {
explicit ProductFilter(std::unordered_set<std::string> products) : products_(products) {
}
- ResourceConfigValueIter SelectProductToKeep(
- const ResourceNameRef& name, const ResourceConfigValueIter begin,
- const ResourceConfigValueIter end, IDiagnostics* diag);
+ ResourceConfigValueIter SelectProductToKeep(const ResourceNameRef& name,
+ const ResourceConfigValueIter begin,
+ const ResourceConfigValueIter end,
+ android::IDiagnostics* diag);
bool Consume(IAaptContext* context, ResourceTable* table) override;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index d432341a8cde..cbf920acc8cf 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -30,16 +30,16 @@ using android::StringPiece;
namespace aapt {
-static bool RequiredNameIsNotEmpty(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool RequiredNameIsNotEmpty(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
if (attr->value.empty()) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'android:name' in <" << el->name << "> tag must not be empty");
return false;
}
@@ -48,7 +48,7 @@ static bool RequiredNameIsNotEmpty(xml::Element* el, SourcePathDiagnostics* diag
// This is how PackageManager builds class names from AndroidManifest.xml entries.
static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
- SourcePathDiagnostics* diag) {
+ android::SourcePathDiagnostics* diag) {
// We allow unqualified class names (ie: .HelloActivity)
// Since we don't know the package name, we can just make a fake one here and
// the test will be identical as long as the real package name is valid too.
@@ -60,51 +60,50 @@ static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
: attr->value;
if (!util::IsJavaClassName(qualified_class_name)) {
- diag->Error(DiagMessage(el->line_number)
- << "attribute 'android:name' in <" << el->name
- << "> tag must be a valid Java class name");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
+ << "> tag must be a valid Java class name");
return false;
}
return true;
}
-static bool OptionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool OptionalNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
return NameIsJavaClassName(el, attr, diag);
}
return true;
}
-static bool RequiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
return NameIsJavaClassName(el, attr, diag);
}
-static bool RequiredNameIsJavaPackage(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
if (!util::IsJavaPackageName(attr->value)) {
- diag->Error(DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
- << "> tag must be a valid Java package name");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
+ << "> tag must be a valid Java package name");
return false;
}
return true;
}
static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
- return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
+ return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
return false;
}
@@ -114,17 +113,17 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std
static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
const std::string& attrName1, const std::string& attrName2) {
- return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
+ return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1);
xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2);
if (attr1 == nullptr && attr2 == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing required attribute 'android:" << attrName1
<< "' or 'android:" << attrName2 << "'");
return false;
}
if (attr1 != nullptr && attr2 != nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> can only specify one of attribute 'android:" << attrName1
<< "' or 'android:" << attrName2 << "'");
return false;
@@ -133,7 +132,7 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
};
}
-static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool AutoGenerateIsFeatureSplit(xml::Element* el, android::SourcePathDiagnostics* diag) {
constexpr const char* kFeatureSplit = "featureSplit";
constexpr const char* kIsFeatureSplit = "isFeatureSplit";
@@ -149,7 +148,7 @@ static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics*
if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
// The isFeatureSplit attribute is false, which conflicts with the use
// of "featureSplit".
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
"is not 'true'");
return false;
@@ -163,7 +162,7 @@ static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics*
return true;
}
-static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool AutoGenerateIsSplitRequired(xml::Element* el, android::SourcePathDiagnostics* diag) {
constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
constexpr const char* kIsSplitRequired = "isSplitRequired";
@@ -175,7 +174,7 @@ static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics*
if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
// The isFeatureSplit attribute is false, which conflicts with the use
// of "featureSplit".
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'requiredSplitTypes' used in <manifest> but "
"'android:isSplitRequired' is not 'true'");
return false;
@@ -189,18 +188,18 @@ static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics*
}
static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
- SourcePathDiagnostics* diag) {
+ android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute({}, "package");
if (!attr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<manifest> tag is missing 'package' attribute");
return false;
} else if (ResourceUtils::IsReference(attr->value)) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'package' in <manifest> tag must not be a reference");
return false;
} else if (!util::IsAndroidPackageName(attr->value)) {
- DiagMessage error_msg(el->line_number);
+ android::DiagMessage error_msg(el->line_number);
error_msg << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
<< attr->value << "'";
if (policy == xml::XmlActionExecutorPolicy::kAllowListWarning) {
@@ -215,8 +214,9 @@ static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy
attr = el->FindAttribute({}, "split");
if (attr) {
if (!util::IsJavaPackageName(attr->value)) {
- diag->Error(DiagMessage(el->line_number) << "attribute 'split' in <manifest> tag is not a "
- "valid split name");
+ diag->Error(android::DiagMessage(el->line_number)
+ << "attribute 'split' in <manifest> tag is not a "
+ "valid split name");
return false;
}
}
@@ -225,11 +225,11 @@ static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy
// The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
// checking on it is manual.
-static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool FixCoreAppAttribute(xml::Element* el, android::SourcePathDiagnostics* diag) {
if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
if (!result) {
- diag->Error(DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
return false;
}
attr->compiled_value = std::move(result);
@@ -238,11 +238,11 @@ static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
}
// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
-static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool VerifyUsesFeature(xml::Element* el, android::SourcePathDiagnostics* diag) {
bool has_name = false;
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
if (attr->value.empty()) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "android:name in <uses-feature> must not be empty");
return false;
}
@@ -252,7 +252,7 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
bool has_gl_es_version = false;
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
if (has_name) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "cannot define both android:name and android:glEsVersion in <uses-feature>");
return false;
}
@@ -260,7 +260,7 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
}
if (!has_name && !has_gl_es_version) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<uses-feature> must have either android:name or android:glEsVersion attribute");
return false;
}
@@ -294,34 +294,29 @@ static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::stri
}
}
-bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
- IDiagnostics* diag) {
+bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) {
// First verify some options.
if (options_.rename_manifest_package) {
if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
- diag->Error(DiagMessage() << "invalid manifest package override '"
- << options_.rename_manifest_package.value()
- << "'");
+ diag->Error(android::DiagMessage() << "invalid manifest package override '"
+ << options_.rename_manifest_package.value() << "'");
return false;
}
}
if (options_.rename_instrumentation_target_package) {
if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "invalid instrumentation target package override '"
- << options_.rename_instrumentation_target_package.value()
- << "'");
+ << options_.rename_instrumentation_target_package.value() << "'");
return false;
}
}
if (options_.rename_overlay_target_package) {
if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
- diag->Error(DiagMessage()
- << "invalid overlay target package override '"
- << options_.rename_overlay_target_package.value()
- << "'");
+ diag->Error(android::DiagMessage() << "invalid overlay target package override '"
+ << options_.rename_overlay_target_package.value() << "'");
return false;
}
}
@@ -614,7 +609,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
TRACE_CALL();
xml::Element* root = xml::FindRootElement(doc->root.get());
if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
- context->GetDiagnostics()->Error(DiagMessage(doc->file.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(doc->file.source)
<< "root tag must be <manifest>");
return false;
}
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index d5d1d1770e1c..5b04cadebacb 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -96,7 +96,7 @@ class ManifestFixer : public IXmlResourceConsumer {
private:
DISALLOW_COPY_AND_ASSIGN(ManifestFixer);
- bool BuildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag);
+ bool BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag);
ManifestFixerOptions options_;
};
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.cpp b/tools/aapt2/link/NoDefaultResourceRemover.cpp
index 05990de6a9b3..2a5163f22e17 100644
--- a/tools/aapt2/link/NoDefaultResourceRemover.cpp
+++ b/tools/aapt2/link/NoDefaultResourceRemover.cpp
@@ -76,15 +76,15 @@ bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* tab
});
for (auto iter = remove_iter; iter != end_iter; ++iter) {
- const ResourceName name(pkg->name, type->type, (*iter)->name);
- IDiagnostics* diag = context->GetDiagnostics();
- diag->Warn(DiagMessage() << "removing resource " << name
- << " without required default value");
+ const ResourceName name(pkg->name, type->named_type, (*iter)->name);
+ android::IDiagnostics* diag = context->GetDiagnostics();
+ diag->Warn(android::DiagMessage()
+ << "removing resource " << name << " without required default value");
if (context->IsVerbose()) {
- diag->Note(DiagMessage() << " did you forget to remove all definitions?");
+ diag->Note(android::DiagMessage() << " did you forget to remove all definitions?");
for (const auto& config_value : (*iter)->values) {
if (config_value->value != nullptr) {
- diag->Note(DiagMessage(config_value->value->GetSource()) << "defined here");
+ diag->Note(android::DiagMessage(config_value->value->GetSource()) << "defined here");
}
}
}
diff --git a/tools/aapt2/link/PrivateAttributeMover.cpp b/tools/aapt2/link/PrivateAttributeMover.cpp
index 675b02a7e161..8c6c743dfff0 100644
--- a/tools/aapt2/link/PrivateAttributeMover.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover.cpp
@@ -57,7 +57,7 @@ OutputIterator move_if(InputContainer& input_container, OutputIterator result, P
bool PrivateAttributeMover::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
if (!type) {
continue;
}
@@ -80,7 +80,8 @@ bool PrivateAttributeMover::Consume(IAaptContext* context, ResourceTable* table)
continue;
}
- ResourceTableType* priv_attr_type = package->FindOrCreateType(ResourceType::kAttrPrivate);
+ auto attr_private_type = ResourceNamedTypeWithDefaultName(ResourceType::kAttrPrivate);
+ ResourceTableType* priv_attr_type = package->FindOrCreateType(attr_private_type);
CHECK(priv_attr_type->entries.empty());
priv_attr_type->entries = std::move(private_attr_entries);
}
diff --git a/tools/aapt2/link/PrivateAttributeMover_test.cpp b/tools/aapt2/link/PrivateAttributeMover_test.cpp
index 168234b36e4a..32335b7f5a9f 100644
--- a/tools/aapt2/link/PrivateAttributeMover_test.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover_test.cpp
@@ -41,13 +41,13 @@ TEST(PrivateAttributeMoverTest, MovePrivateAttributes) {
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(package, nullptr);
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
EXPECT_NE(type->FindEntry("publicA"), nullptr);
EXPECT_NE(type->FindEntry("publicB"), nullptr);
- type = package->FindType(ResourceType::kAttrPrivate);
+ type = package->FindTypeWithDefaultName(ResourceType::kAttrPrivate);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
EXPECT_NE(type->FindEntry("privateA"), nullptr);
@@ -68,11 +68,11 @@ TEST(PrivateAttributeMoverTest, LeavePrivateAttributesWhenNoPublicAttributesDefi
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(package, nullptr);
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
- type = package->FindType(ResourceType::kAttrPrivate);
+ type = package->FindTypeWithDefaultName(ResourceType::kAttrPrivate);
ASSERT_EQ(type, nullptr);
}
@@ -87,12 +87,12 @@ TEST(PrivateAttributeMoverTest, DoNotCreatePrivateAttrsIfNoneExist) {
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(nullptr, package);
- ASSERT_EQ(nullptr, package->FindType(ResourceType::kAttrPrivate));
+ ASSERT_EQ(nullptr, package->FindTypeWithDefaultName(ResourceType::kAttrPrivate));
PrivateAttributeMover mover;
ASSERT_TRUE(mover.Consume(context.get(), table.get()));
- ASSERT_EQ(nullptr, package->FindType(ResourceType::kAttrPrivate));
+ ASSERT_EQ(nullptr, package->FindTypeWithDefaultName(ResourceType::kAttrPrivate));
}
} // namespace aapt
diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/link/ProductFilter.cpp
index 793740af3021..9544986fda76 100644
--- a/tools/aapt2/link/ProductFilter.cpp
+++ b/tools/aapt2/link/ProductFilter.cpp
@@ -23,7 +23,7 @@ namespace aapt {
ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
const ResourceNameRef& name, const ResourceConfigValueIter begin,
- const ResourceConfigValueIter end, IDiagnostics* diag) {
+ const ResourceConfigValueIter end, android::IDiagnostics* diag) {
ResourceConfigValueIter default_product_iter = end;
ResourceConfigValueIter selected_product_iter = end;
@@ -32,16 +32,15 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
if (products_.find(config_value->product) != products_.end()) {
if (selected_product_iter != end) {
// We have two possible values for this product!
- diag->Error(DiagMessage(config_value->value->GetSource())
- << "selection of product '" << config_value->product
- << "' for resource " << name << " is ambiguous");
+ diag->Error(android::DiagMessage(config_value->value->GetSource())
+ << "selection of product '" << config_value->product << "' for resource "
+ << name << " is ambiguous");
ResourceConfigValue* previously_selected_config_value =
selected_product_iter->get();
- diag->Note(
- DiagMessage(previously_selected_config_value->value->GetSource())
- << "product '" << previously_selected_config_value->product
- << "' is also a candidate");
+ diag->Note(android::DiagMessage(previously_selected_config_value->value->GetSource())
+ << "product '" << previously_selected_config_value->product
+ << "' is also a candidate");
return end;
}
@@ -52,15 +51,13 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
if (config_value->product.empty() || config_value->product == "default") {
if (default_product_iter != end) {
// We have two possible default values.
- diag->Error(DiagMessage(config_value->value->GetSource())
- << "multiple default products defined for resource "
- << name);
+ diag->Error(android::DiagMessage(config_value->value->GetSource())
+ << "multiple default products defined for resource " << name);
ResourceConfigValue* previously_default_config_value =
default_product_iter->get();
- diag->Note(
- DiagMessage(previously_default_config_value->value->GetSource())
- << "default product also defined here");
+ diag->Note(android::DiagMessage(previously_default_config_value->value->GetSource())
+ << "default product also defined here");
return end;
}
@@ -70,8 +67,7 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
}
if (default_product_iter == end) {
- diag->Error(DiagMessage() << "no default product defined for resource "
- << name);
+ diag->Error(android::DiagMessage() << "no default product defined for resource " << name);
return end;
}
@@ -98,7 +94,7 @@ bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) {
// End of the array, or we saw a different config,
// so this must be the end of a range of products.
// Select the product to keep from the set of products defined.
- ResourceNameRef name(pkg->name, type->type, entry->name);
+ ResourceNameRef name(pkg->name, type->named_type, entry->name);
auto value_to_keep = SelectProductToKeep(
name, start_range_iter, iter, context->GetDiagnostics());
if (value_to_keep == iter) {
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index 4f78bbcece33..2cb9afa05cad 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -31,27 +31,29 @@ TEST(ProductFilterTest, SelectTwoProducts) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("land/default.xml")).Build(), land)
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/default.xml")).Build(),
+ land)
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("land/tablet.xml")).Build(), land,
- "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/tablet.xml")).Build(),
+ land, "tablet")
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("port/default.xml")).Build(), port)
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/default.xml")).Build(),
+ port)
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("port/tablet.xml")).Build(), port,
- "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/tablet.xml")).Build(),
+ port, "tablet")
.Build(),
context->GetDiagnostics()));
@@ -74,13 +76,14 @@ TEST(ProductFilterTest, SelectDefaultProduct) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build())
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(), {}, "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
+ "tablet")
.Build(),
context->GetDiagnostics()));
;
@@ -102,20 +105,21 @@ TEST(ProductFilterTest, FailOnAmbiguousProduct) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build())
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(), {}, "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
+ "tablet")
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("no-sdcard.xml")).Build(), {},
- "no-sdcard")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("no-sdcard.xml")).Build(),
+ {}, "no-sdcard")
.Build(),
context->GetDiagnostics()));
@@ -127,15 +131,15 @@ TEST(ProductFilterTest, FailOnMultipleDefaults) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
ResourceTable table;
- ASSERT_TRUE(
- table.AddResource(NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source(".xml")).Build())
- .Build(),
- context->GetDiagnostics()));
+ ASSERT_TRUE(table.AddResource(
+ NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source(".xml")).Build())
+ .Build(),
+ context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build(), {},
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build(), {},
"default")
.Build(),
context->GetDiagnostics()));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 5372cf243951..f2a93a868bb7 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -16,16 +16,15 @@
#include "link/ReferenceLinker.h"
-#include "android-base/logging.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "Diagnostics.h"
#include "ResourceParser.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
#include "link/Linkers.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -82,7 +81,7 @@ std::unique_ptr<Reference> ReferenceLinkerTransformer::TransformDerived(const Re
if (auto ref = ValueCast<Reference>(linked_item_ptr)) {
return std::unique_ptr<Reference>(ref);
}
- context_->GetDiagnostics()->Error(DiagMessage(value->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(value->GetSource())
<< "value of '"
<< LoggingResourceName(*value, callsite_, package_decls_)
<< "' must be a resource reference");
@@ -130,7 +129,7 @@ std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style*
// check is fast and we avoid creating a DiagMessage when the match is successful.
if (!symbol->attribute->Matches(*entry.value, nullptr)) {
// The actual type of this item is incompatible with the attribute.
- DiagMessage msg(entry.key.GetSource());
+ android::DiagMessage msg(entry.key.GetSource());
// Call the matches method again, this time with a DiagMessage so we fill in the actual
// error message.
@@ -139,7 +138,7 @@ std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style*
error_ = true;
}
} else {
- context_->GetDiagnostics()->Error(DiagMessage(entry.key.GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(entry.key.GetSource())
<< "style attribute '"
<< LoggingResourceName(entry.key, callsite_, package_decls_)
<< "' " << err_str);
@@ -344,7 +343,7 @@ std::optional<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Ref
void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
const xml::IPackageDeclStack* decls,
- DiagMessage* out_msg) {
+ android::DiagMessage* out_msg) {
CHECK(out_msg != nullptr);
if (!ref.name) {
*out_msg << ref.id.value();
@@ -393,7 +392,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
auto result = table->FindResource(transformed_reference.name.value());
if (!result || result.value().entry->values.empty()) {
context->GetDiagnostics()->Error(
- DiagMessage(reference.GetSource())
+ android::DiagMessage(reference.GetSource())
<< "failed to find definition for "
<< LoggingResourceName(transformed_reference, callsite, decls));
return {};
@@ -424,7 +423,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
macro_values[0]->config, *context->GetDiagnostics());
if (new_value == nullptr) {
context->GetDiagnostics()->Error(
- DiagMessage(reference.GetSource())
+ android::DiagMessage(reference.GetSource())
<< "failed to substitute macro "
<< LoggingResourceName(transformed_reference, callsite, decls)
<< ": failed to parse contents as one of type(s) " << Attribute::MaskString(type_flags));
@@ -450,7 +449,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
return std::move(new_ref);
}
- context->GetDiagnostics()->Error(DiagMessage(reference.GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(reference.GetSource())
<< "resource "
<< LoggingResourceName(transformed_reference, callsite, decls)
<< " " << err_str);
@@ -468,22 +467,21 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
// First, unmangle the name if necessary.
- ResourceName name(package->name, type->type, entry->name);
+ ResourceName name(package->name, type->named_type, entry->name);
NameMangler::Unmangle(&name.entry, &name.package);
// Symbol state information may be lost if there is no value for the resource.
if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source)
- << "no definition for declared symbol '" << name
- << "'");
+ context->GetDiagnostics()->Error(android::DiagMessage(entry->visibility.source)
+ << "no definition for declared symbol '" << name << "'");
error = true;
}
// Ensure that definitions for values declared as overlayable exist
if (entry->overlayable_item && entry->values.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source)
- << "no definition for overlayable symbol '"
- << name << "'");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(entry->overlayable_item.value().source)
+ << "no definition for overlayable symbol '" << name << "'");
error = true;
}
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index b46085397c52..9fb25e1bc2c9 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -32,7 +32,7 @@ namespace aapt {
class ReferenceLinkerTransformer : public CloningValueTransformer {
public:
ReferenceLinkerTransformer(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
- StringPool* string_pool, ResourceTable* table,
+ android::StringPool* string_pool, ResourceTable* table,
xml::IPackageDeclStack* decl)
: CloningValueTransformer(string_pool),
callsite_(callsite),
@@ -110,7 +110,8 @@ class ReferenceLinker : public IResourceTableConsumer {
// Same as WriteResourceName but omits the 'attr' part.
static void WriteAttributeName(const Reference& ref, const CallSite& callsite,
- const xml::IPackageDeclStack* decls, DiagMessage* out_msg);
+ const xml::IPackageDeclStack* decls,
+ android::DiagMessage* out_msg);
// Returns a fully linked version a resource reference.
//
diff --git a/tools/aapt2/link/ResourceExcluder.cpp b/tools/aapt2/link/ResourceExcluder.cpp
index b3b9dc47fd84..59393cbd0add 100644
--- a/tools/aapt2/link/ResourceExcluder.cpp
+++ b/tools/aapt2/link/ResourceExcluder.cpp
@@ -50,12 +50,9 @@ void RemoveIfExcluded(std::set<std::pair<ConfigDescription, int>>& excluded_conf
if (masked_diff == 0) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(
- DiagMessage(value->value->GetSource())
- << "excluded resource \""
- << entry->name
- << "\" with config "
- << config.toString());
+ context->GetDiagnostics()->Note(android::DiagMessage(value->value->GetSource())
+ << "excluded resource \"" << entry->name
+ << "\" with config " << config.toString());
}
value->value = {};
return;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index d78f0ac17f67..c9f0964193d2 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,7 +37,7 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
CHECK(main_package_ != nullptr) << "package name or ID already taken";
}
-bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
+bool TableMerger::Merge(const android::Source& src, ResourceTable* table, bool overlay) {
TRACE_CALL();
// We allow adding new resources if this is not an overlay, or if the options allow overlays
// to add new resources.
@@ -45,7 +45,8 @@ bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
}
// This will merge packages with the same package name (or no package name).
-bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overlay, bool allow_new) {
+bool TableMerger::MergeImpl(const android::Source& src, ResourceTable* table, bool overlay,
+ bool allow_new) {
bool error = false;
for (auto& package : table->packages) {
// Only merge an empty package or the package we're building.
@@ -65,13 +66,14 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overla
// This will merge and mangle resources from a static library. It is assumed that all FileReferences
// have correctly set their io::IFile*.
-bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name,
+bool TableMerger::MergeAndMangle(const android::Source& src, const StringPiece& package_name,
ResourceTable* table) {
bool error = false;
for (auto& package : table->packages) {
// Warn of packages with an unrelated ID.
if (package_name != package->name) {
- context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " << package->name);
+ context_->GetDiagnostics()->Warn(android::DiagMessage(src)
+ << "ignoring package " << package->name);
continue;
}
@@ -82,8 +84,8 @@ bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_n
return !error;
}
-static bool MergeType(IAaptContext* context, const Source& src, ResourceTableType* dst_type,
- ResourceTableType* src_type) {
+static bool MergeType(IAaptContext* context, const android::Source& src,
+ ResourceTableType* dst_type, ResourceTableType* src_type) {
if (src_type->visibility_level >= dst_type->visibility_level) {
// The incoming type's visibility is stronger, so we should override the visibility.
dst_type->visibility_level = src_type->visibility_level;
@@ -91,15 +93,15 @@ static bool MergeType(IAaptContext* context, const Source& src, ResourceTableTyp
return true;
}
-static bool MergeEntry(IAaptContext* context, const Source& src,
- ResourceEntry* dst_entry, ResourceEntry* src_entry,
- bool strict_visibility) {
+static bool MergeEntry(IAaptContext* context, const android::Source& src, ResourceEntry* dst_entry,
+ ResourceEntry* src_entry, bool strict_visibility) {
if (strict_visibility
&& dst_entry->visibility.level != Visibility::Level::kUndefined
&& src_entry->visibility.level != dst_entry->visibility.level) {
- context->GetDiagnostics()->Error(
- DiagMessage(src) << "cannot merge resource '" << dst_entry->name << "' with conflicting visibilities: "
- << "public and private");
+ context->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "cannot merge resource '" << dst_entry->name
+ << "' with conflicting visibilities: "
+ << "public and private");
return false;
}
@@ -114,8 +116,9 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
dst_entry->visibility.level == Visibility::Level::kPublic && dst_entry->id &&
src_entry->id && src_entry->id != dst_entry->id) {
// Both entries are public and have different IDs.
- context->GetDiagnostics()->Error(DiagMessage(src) << "cannot merge entry '" << src_entry->name
- << "': conflicting public IDs");
+ context->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "cannot merge entry '" << src_entry->name
+ << "': conflicting public IDs");
return false;
}
@@ -139,11 +142,12 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
// Do not allow a resource with an overlayable declaration to have that overlayable
// declaration redefined.
- context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source)
- << "duplicate overlayable declaration for resource '"
- << src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source)
- << "previous declaration here");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(src_entry->overlayable_item.value().source)
+ << "duplicate overlayable declaration for resource '" << src_entry->name << "'");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(dst_entry->overlayable_item.value().source)
+ << "previous declaration here");
return false;
}
}
@@ -154,10 +158,10 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
if (src_entry->staged_id) {
if (dst_entry->staged_id &&
dst_entry->staged_id.value().id != src_entry->staged_id.value().id) {
- context->GetDiagnostics()->Error(DiagMessage(src_entry->staged_id.value().source)
+ context->GetDiagnostics()->Error(android::DiagMessage(src_entry->staged_id.value().source)
<< "conflicting staged id declaration for resource '"
<< src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->staged_id.value().source)
+ context->GetDiagnostics()->Error(android::DiagMessage(dst_entry->staged_id.value().source)
<< "previous declaration here");
}
dst_entry->staged_id = std::move(src_entry->staged_id);
@@ -174,7 +178,7 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
// If both values are Styleables/Styles, we just merge them into the existing value.
static ResourceTable::CollisionResult ResolveMergeCollision(
bool override_styles_instead_of_overlaying, Value* existing, Value* incoming,
- StringPool* pool) {
+ android::StringPool* pool) {
if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) {
if (Styleable* incoming_styleable = ValueCast<Styleable>(incoming)) {
// Styleables get merged.
@@ -194,13 +198,10 @@ static ResourceTable::CollisionResult ResolveMergeCollision(
return ResourceTable::ResolveValueCollision(existing, incoming);
}
-static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
- const ResourceNameRef& res_name,
- bool overlay,
- bool override_styles_instead_of_overlaying,
- ResourceConfigValue* dst_config_value,
- ResourceConfigValue* src_config_value,
- StringPool* pool) {
+static ResourceTable::CollisionResult MergeConfigValue(
+ IAaptContext* context, const ResourceNameRef& res_name, bool overlay,
+ bool override_styles_instead_of_overlaying, ResourceConfigValue* dst_config_value,
+ ResourceConfigValue* src_config_value, android::StringPool* pool) {
using CollisionResult = ResourceTable::CollisionResult;
Value* dst_value = dst_config_value->value.get();
@@ -220,22 +221,22 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
}
// Error!
- context->GetDiagnostics()->Error(DiagMessage(src_value->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(src_value->GetSource())
<< "resource '" << res_name << "' has a conflicting value for "
<< "configuration (" << src_config_value->config << ")");
- context->GetDiagnostics()->Note(DiagMessage(dst_value->GetSource())
+ context->GetDiagnostics()->Note(android::DiagMessage(dst_value->GetSource())
<< "originally defined here");
return CollisionResult::kConflict;
}
return collision_result;
}
-bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
- bool overlay, bool allow_new_resources) {
+bool TableMerger::DoMerge(const android::Source& src, ResourceTablePackage* src_package,
+ bool mangle_package, bool overlay, bool allow_new_resources) {
bool error = false;
for (auto& src_type : src_package->types) {
- ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->type);
+ ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->named_type);
if (!MergeType(context_, src, dst_type, src_type.get())) {
error = true;
continue;
@@ -254,14 +255,15 @@ bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package,
dst_entry = dst_type->FindEntry(entry_name);
}
- const ResourceNameRef res_name(src_package->name, src_type->type, src_entry->name);
+ const ResourceNameRef res_name(src_package->name, src_type->named_type, src_entry->name);
if (!dst_entry) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "resource " << res_name
<< " does not override an existing resource");
- context_->GetDiagnostics()->Note(DiagMessage(src) << "define an <add-resource> tag or use "
- << "--auto-add-overlay");
+ context_->GetDiagnostics()->Note(android::DiagMessage(src)
+ << "define an <add-resource> tag or use "
+ << "--auto-add-overlay");
error = true;
continue;
}
@@ -349,7 +351,7 @@ bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFi
file_ref->file = file;
ResourceTablePackage* pkg = table.FindOrCreatePackage(file_desc.name.package);
- pkg->FindOrCreateType(file_desc.name.type.type)
+ pkg->FindOrCreateType(file_desc.name.type)
->FindOrCreateEntry(file_desc.name.entry)
->FindOrCreateValue(file_desc.config, {})
->value = std::move(file_ref);
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index e01a0c186392..2ba212372966 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -67,11 +67,12 @@ class TableMerger {
// Merges resources from the same or empty package. This is for local sources.
// If overlay is true, the resources are treated as overlays.
- bool Merge(const Source& src, ResourceTable* table, bool overlay);
+ bool Merge(const android::Source& src, ResourceTable* table, bool overlay);
// Merges resources from the given package, mangling the name. This is for static libraries.
// All FileReference values must have their io::IFile set.
- bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table);
+ bool MergeAndMangle(const android::Source& src, const android::StringPiece& package,
+ ResourceTable* table);
// Merges a compiled file that belongs to this same or empty package.
bool MergeFile(const ResourceFile& fileDesc, bool overlay, io::IFile* file);
@@ -85,9 +86,10 @@ class TableMerger {
ResourceTablePackage* main_package_;
std::set<std::string> merged_packages_;
- bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
+ bool MergeImpl(const android::Source& src, ResourceTable* src_table, bool overlay,
+ bool allow_new);
- bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+ bool DoMerge(const android::Source& src, ResourceTablePackage* src_package, bool mangle_package,
bool overlay, bool allow_new_resources);
std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 4cbf2d3a826c..56a7c3b55f8d 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -94,7 +94,7 @@ TEST_F(TableMergerTest, MergeFile) {
ResourceFile file_desc;
file_desc.config = test::ParseConfigOrDie("hdpi-v4");
file_desc.name = test::ParseNameOrDie("layout/main");
- file_desc.source = Source("res/layout-hdpi/main.xml");
+ file_desc.source = android::Source("res/layout-hdpi/main.xml");
test::TestFile test_file("path/to/res/layout-hdpi/main.xml.flat");
ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &test_file));
diff --git a/tools/aapt2/link/XmlCompatVersioner.cpp b/tools/aapt2/link/XmlCompatVersioner.cpp
index 957b64cd8dbb..482c227a3670 100644
--- a/tools/aapt2/link/XmlCompatVersioner.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner.cpp
@@ -22,7 +22,7 @@
namespace aapt {
-static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string_pool) {
+static xml::Attribute CopyAttr(const xml::Attribute& src, android::StringPool* out_string_pool) {
CloningValueTransformer cloner(out_string_pool);
xml::Attribute dst{src.namespace_uri, src.name, src.value, src.compiled_attribute};
if (src.compiled_value != nullptr) {
@@ -34,7 +34,7 @@ static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string
// Returns false if the attribute is not copied because an existing attribute takes precedence
// (came from a rule).
static bool CopyAttribute(const xml::Attribute& src_attr, bool generated, xml::Element* dst_el,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
CloningValueTransformer cloner(out_string_pool);
xml::Attribute* dst_attr = dst_el->FindAttribute(src_attr.namespace_uri, src_attr.name);
if (dst_attr != nullptr) {
@@ -58,7 +58,7 @@ void XmlCompatVersioner::ProcessRule(const xml::Element& src_el, const xml::Attr
const util::Range<ApiVersion>& api_range, bool generated,
xml::Element* dst_el,
std::set<ApiVersion>* out_apis_referenced,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
if (src_attr_version <= api_range.start) {
// The API is compatible, so don't check the rule and just copy.
if (!CopyAttribute(src_attr, generated, dst_el, out_string_pool)) {
@@ -156,7 +156,7 @@ DegradeToManyRule::DegradeToManyRule(std::vector<ReplacementAttr> attrs)
}
static inline std::unique_ptr<Item> CloneIfNotNull(const std::unique_ptr<Item>& src,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
if (src == nullptr) {
return {};
}
@@ -166,7 +166,7 @@ static inline std::unique_ptr<Item> CloneIfNotNull(const std::unique_ptr<Item>&
std::vector<DegradeResult> DegradeToManyRule::Degrade(const xml::Element& src_el,
const xml::Attribute& src_attr,
- StringPool* out_string_pool) const {
+ android::StringPool* out_string_pool) const {
std::vector<DegradeResult> result;
result.reserve(attrs_.size());
for (const ReplacementAttr& attr : attrs_) {
diff --git a/tools/aapt2/link/XmlCompatVersioner.h b/tools/aapt2/link/XmlCompatVersioner.h
index 998061806279..22f98281b7ac 100644
--- a/tools/aapt2/link/XmlCompatVersioner.h
+++ b/tools/aapt2/link/XmlCompatVersioner.h
@@ -45,7 +45,7 @@ class IDegradeRule {
virtual std::vector<DegradeResult> Degrade(const xml::Element& src_el,
const xml::Attribute& src_attr,
- StringPool* out_string_pool) const = 0;
+ android::StringPool* out_string_pool) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(IDegradeRule);
@@ -70,7 +70,7 @@ class XmlCompatVersioner {
void ProcessRule(const xml::Element& src_el, const xml::Attribute& src_attr,
const ApiVersion& src_attr_version, const IDegradeRule* rule,
const util::Range<ApiVersion>& api_range, bool generated, xml::Element* dst_el,
- std::set<ApiVersion>* out_apis_referenced, StringPool* out_string_pool);
+ std::set<ApiVersion>* out_apis_referenced, android::StringPool* out_string_pool);
const Rules* rules_;
};
@@ -87,7 +87,7 @@ class DegradeToManyRule : public IDegradeRule {
virtual ~DegradeToManyRule() = default;
std::vector<DegradeResult> Degrade(const xml::Element& src_el, const xml::Attribute& src_attr,
- StringPool* out_string_pool) const override;
+ android::StringPool* out_string_pool) const override;
private:
DISALLOW_COPY_AND_ASSIGN(DegradeToManyRule);
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 1f8548b5de75..d2e9bd770a31 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "link/Linkers.h"
-
-#include "androidfw/ResourceTypes.h"
-
-#include "Diagnostics.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "link/Linkers.h"
#include "link/ReferenceLinker.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -38,7 +36,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
public:
using xml::PackageAwareVisitor::Visit;
- XmlVisitor(const Source& source, StringPool* pool, const CallSite& callsite,
+ XmlVisitor(const android::Source& source, android::StringPool* pool, const CallSite& callsite,
IAaptContext* context, ResourceTable* table, SymbolTable* symbols)
: source_(source),
callsite_(callsite),
@@ -61,7 +59,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
}
}
- const Source source = source_.WithLine(el->line_number);
+ const android::Source source = source_.WithLine(el->line_number);
for (xml::Attribute& attr : el->attributes) {
// If the attribute has no namespace, interpret values as if
// they were assigned to the default Attribute.
@@ -80,7 +78,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, context_, symbols_, &err_str);
if (!attr.compiled_attribute) {
- DiagMessage error_msg(source);
+ android::DiagMessage error_msg(source);
error_msg << "attribute ";
ReferenceLinker::WriteAttributeName(attr_ref, callsite_, this, &error_msg);
error_msg << " " << err_str;
@@ -99,7 +97,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
attr.compiled_value = attr.compiled_value->Transform(reference_transformer_);
} else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) {
// We won't be able to encode this as a string.
- DiagMessage msg(source);
+ android::DiagMessage msg(source);
msg << "'" << attr.value << "' is incompatible with attribute " << attr.name << " "
<< *attribute;
context_->GetDiagnostics()->Error(msg);
@@ -118,7 +116,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
private:
DISALLOW_COPY_AND_ASSIGN(XmlVisitor);
- Source source_;
+ android::Source source_;
const CallSite& callsite_;
IAaptContext* context_;
SymbolTable* symbols_;
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index c686a10a3fa9..f994e27e4e5b 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -65,7 +65,7 @@ class ContextWrapper : public IAaptContext {
return context_->GetExternalSymbols();
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
if (source_diag_) {
return source_diag_.get();
}
@@ -97,8 +97,8 @@ class ContextWrapper : public IAaptContext {
}
void SetSource(const std::string& source) {
- source_diag_ =
- util::make_unique<SourcePathDiagnostics>(Source{source}, context_->GetDiagnostics());
+ source_diag_ = util::make_unique<android::SourcePathDiagnostics>(android::Source{source},
+ context_->GetDiagnostics());
}
const std::set<std::string>& GetSplitNameDependencies() override {
@@ -107,7 +107,7 @@ class ContextWrapper : public IAaptContext {
private:
IAaptContext* context_;
- std::unique_ptr<SourcePathDiagnostics> source_diag_;
+ std::unique_ptr<android::SourcePathDiagnostics> source_diag_;
int min_sdk_ = -1;
};
@@ -143,7 +143,8 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
if (it == artifacts_to_keep.end()) {
filtered_artifacts.insert(artifact.name);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(artifact.name) << "skipping artifact");
+ context_->GetDiagnostics()->Note(android::DiagMessage(artifact.name)
+ << "skipping artifact");
}
continue;
} else {
@@ -158,28 +159,29 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
return false;
}
- IDiagnostics* diag = wrapped_context.GetDiagnostics();
+ android::IDiagnostics* diag = wrapped_context.GetDiagnostics();
std::unique_ptr<XmlResource> manifest;
if (!UpdateManifest(artifact, &manifest, diag)) {
- diag->Error(DiagMessage() << "could not update AndroidManifest.xml for output artifact");
+ diag->Error(android::DiagMessage()
+ << "could not update AndroidManifest.xml for output artifact");
return false;
}
std::string out = options.out_dir;
if (!file::mkdirs(out)) {
- diag->Warn(DiagMessage() << "could not create out dir: " << out);
+ diag->Warn(android::DiagMessage() << "could not create out dir: " << out);
}
file::AppendPath(&out, artifact.name);
if (context_->IsVerbose()) {
- diag->Note(DiagMessage() << "Generating split: " << out);
+ diag->Note(android::DiagMessage() << "Generating split: " << out);
}
std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(diag, out);
if (context_->IsVerbose()) {
- diag->Note(DiagMessage() << "Writing output: " << out);
+ diag->Note(android::DiagMessage() << "Writing output: " << out);
}
filters.AddFilter(util::make_unique<SignatureFilter>());
@@ -192,22 +194,25 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
// Make sure all of the requested artifacts were valid. If there are any kept artifacts left,
// either the config or the command line was wrong.
if (!artifacts_to_keep.empty()) {
- context_->GetDiagnostics()->Error(
- DiagMessage() << "The configuration and command line to filter artifacts do not match");
+ context_->GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "The configuration and command line to filter artifacts do not match");
- context_->GetDiagnostics()->Error(DiagMessage() << kept_artifacts.size() << " kept:");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << kept_artifacts.size() << " kept:");
for (const auto& artifact : kept_artifacts) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
- context_->GetDiagnostics()->Error(DiagMessage() << filtered_artifacts.size() << " filtered:");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << filtered_artifacts.size() << " filtered:");
for (const auto& artifact : filtered_artifacts) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
- context_->GetDiagnostics()->Error(DiagMessage() << artifacts_to_keep.size() << " missing:");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << artifacts_to_keep.size() << " missing:");
for (const auto& artifact : artifacts_to_keep) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
return false;
@@ -250,7 +255,8 @@ std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(IAaptContext* cont
VersionCollapser collapser;
if (!collapser.Consume(&wrapped_context, table.get())) {
- context->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "Failed to strip versioned resources");
return {};
}
@@ -261,7 +267,7 @@ std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(IAaptContext* cont
bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
std::unique_ptr<XmlResource>* updated_manifest,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
const xml::XmlResource* apk_manifest = apk_->GetManifest();
if (apk_manifest == nullptr) {
return false;
@@ -277,20 +283,21 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
}
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(manifest->file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(manifest->file.source) << "root tag must be <manifest>");
return false;
}
// Retrieve the versionCode attribute.
auto version_code = manifest_el->FindAttribute(kSchemaAndroid, "versionCode");
if (!version_code) {
- diag->Error(DiagMessage(manifest->file.source) << "manifest must have a versionCode attribute");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "manifest must have a versionCode attribute");
return false;
}
auto version_code_value = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
if (!version_code_value) {
- diag->Error(DiagMessage(manifest->file.source) << "versionCode is invalid");
+ diag->Error(android::DiagMessage(manifest->file.source) << "versionCode is invalid");
return false;
}
@@ -300,7 +307,7 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
if (version_code_major) {
version_code_major_value = ValueCast<BinaryPrimitive>(version_code_major->compiled_value.get());
if (!version_code_major_value) {
- diag->Error(DiagMessage(manifest->file.source) << "versionCodeMajor is invalid");
+ diag->Error(android::DiagMessage(manifest->file.source) << "versionCodeMajor is invalid");
return false;
}
}
@@ -325,13 +332,15 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
} else {
// There was no minSdkVersion. This is strange since at this point we should have been
// through the manifest fixer which sets the default minSdkVersion.
- diag->Error(DiagMessage(manifest->file.source) << "missing minSdkVersion from <uses-sdk>");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "missing minSdkVersion from <uses-sdk>");
return false;
}
} else {
// No uses-sdk present. This is strange since at this point we should have been
// through the manifest fixer which should have added it.
- diag->Error(DiagMessage(manifest->file.source) << "missing <uses-sdk> from <manifest>");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "missing <uses-sdk> from <manifest>");
return false;
}
}
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index 4a5a6c3d5915..8d8ed651a763 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -22,10 +22,9 @@
#include <unordered_set>
#include <vector>
-#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
#include "LoadedApk.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "configuration/ConfigurationParser.h"
namespace aapt {
@@ -58,12 +57,13 @@ class MultiApkGenerator {
FilterChain* chain);
private:
- IDiagnostics* GetDiagnostics() {
+ android::IDiagnostics* GetDiagnostics() {
return context_->GetDiagnostics();
}
bool UpdateManifest(const configuration::OutputArtifact& artifact,
- std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+ std::unique_ptr<xml::XmlResource>* updated_manifest,
+ android::IDiagnostics* diag);
/**
* Adds the <screen> elements to the parent node for the provided density configuration.
diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp
index 0278b439cfae..c71cb4c21020 100644
--- a/tools/aapt2/optimize/ResourceDeduper.cpp
+++ b/tools/aapt2/optimize/ResourceDeduper.cpp
@@ -77,12 +77,11 @@ class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor {
}
}
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(
- DiagMessage(node_value->value->GetSource())
- << "removing dominated duplicate resource with name \""
- << entry_->name << "\"");
- context_->GetDiagnostics()->Note(
- DiagMessage(parent_value->value->GetSource()) << "dominated here");
+ context_->GetDiagnostics()->Note(android::DiagMessage(node_value->value->GetSource())
+ << "removing dominated duplicate resource with name \""
+ << entry_->name << "\"");
+ context_->GetDiagnostics()->Note(android::DiagMessage(parent_value->value->GetSource())
+ << "dominated here");
}
node_value->value = {};
}
diff --git a/tools/aapt2/optimize/ResourceFilter.cpp b/tools/aapt2/optimize/ResourceFilter.cpp
index 08c045bf68f7..db84b66ecd2d 100644
--- a/tools/aapt2/optimize/ResourceFilter.cpp
+++ b/tools/aapt2/optimize/ResourceFilter.cpp
@@ -28,7 +28,7 @@ bool ResourceFilter::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto it = type->entries.begin(); it != type->entries.end(); ) {
- ResourceName resource = ResourceName({}, type->type, (*it)->name);
+ ResourceName resource = ResourceName({}, type->named_type, (*it)->name);
if (exclude_list_.find(resource) != exclude_list_.end()) {
it = type->entries.erase(it);
} else {
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 9c4b323db433..e41e45a29b3e 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -22,11 +22,11 @@
#include <set>
#include <sstream>
-#include "Diagnostics.h"
#include "NameMangler.h"
#include "Resource.h"
#include "ResourceValues.h"
-#include "Source.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
namespace aapt {
@@ -45,7 +45,7 @@ struct IAaptContext {
virtual PackageType GetPackageType() = 0;
virtual SymbolTable* GetExternalSymbols() = 0;
- virtual IDiagnostics* GetDiagnostics() = 0;
+ virtual android::IDiagnostics* GetDiagnostics() = 0;
virtual const std::string& GetCompilationPackage() = 0;
virtual uint8_t GetPackageId() = 0;
virtual NameMangler* GetNameMangler() = 0;
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index ddc210189793..e576709a776d 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -17,9 +17,9 @@
#include "process/SymbolTable.h"
#include "SdkConstants.h"
+#include "androidfw/BigBuffer.h"
#include "format/binary/TableFlattener.h"
#include "test/Test.h"
-#include "util/BigBuffer.h"
using ::testing::Eq;
using ::testing::IsNull;
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 116b2ab9aa98..58f2b1dcdf87 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -160,17 +160,15 @@ bool TableSplitter::VerifySplitConstraints(IAaptContext* context) {
for (size_t i = 0; i < split_constraints_.size(); i++) {
if (split_constraints_[i].configs.size() == 0) {
// For now, treat this as a warning. We may consider aborting processing.
- context->GetDiagnostics()->Warn(DiagMessage()
- << "no configurations for constraint '"
- << split_constraints_[i].name << "'");
+ context->GetDiagnostics()->Warn(android::DiagMessage() << "no configurations for constraint '"
+ << split_constraints_[i].name << "'");
}
for (size_t j = i + 1; j < split_constraints_.size(); j++) {
for (const ConfigDescription& config : split_constraints_[i].configs) {
if (split_constraints_[j].configs.find(config) != split_constraints_[j].configs.end()) {
- context->GetDiagnostics()->Error(DiagMessage()
- << "config '" << config
- << "' appears in multiple splits, "
- << "target split ambiguous");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage() << "config '" << config << "' appears in multiple splits, "
+ << "target split ambiguous");
error = true;
}
}
@@ -189,7 +187,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
}
for (auto& type : pkg->types) {
- if (type->type == ResourceType::kMipmap) {
+ if (type->named_type.type == ResourceType::kMipmap) {
// Always keep mipmaps.
continue;
}
@@ -241,7 +239,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
// Create the same resource structure in the split. We do this lazily because we might
// not have actual values for each type/entry.
ResourceTablePackage* split_pkg = split_table->FindPackage(pkg->name);
- ResourceTableType* split_type = split_pkg->FindOrCreateType(type->type);
+ ResourceTableType* split_type = split_pkg->FindOrCreateType(type->named_type);
split_type->visibility_level = type->visibility_level;
ResourceEntry* split_entry = split_type->FindOrCreateEntry(entry->name);
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 23331de02df7..30336e27b907 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -16,9 +16,9 @@
#include "test/Builders.h"
+#include "Diagnostics.h"
#include "android-base/logging.h"
#include "androidfw/StringPiece.h"
-
#include "io/StringStream.h"
#include "test/Common.h"
#include "util/Util.h"
@@ -151,7 +151,7 @@ ResourceTableBuilder& ResourceTableBuilder::Add(NewResource&& res) {
return *this;
}
-StringPool* ResourceTableBuilder::string_pool() {
+android::StringPool* ResourceTableBuilder::string_pool() {
return &table_->string_pool;
}
@@ -235,7 +235,7 @@ std::unique_ptr<xml::XmlResource> BuildXmlDom(const StringPiece& str) {
input.append(str.data(), str.size());
StringInputStream in(input);
StdErrDiagnostics diag;
- std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, &diag, Source("test.xml"));
+ std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, &diag, android::Source("test.xml"));
CHECK(doc != nullptr && doc->root != nullptr) << "failed to parse inline XML string";
return doc;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 55778aea40af..780bd0df8f16 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -75,7 +75,7 @@ class ResourceTableBuilder {
const OverlayableItem& overlayable);
ResourceTableBuilder& Add(NewResource&& res);
- StringPool* string_pool();
+ android::StringPool* string_pool();
std::unique_ptr<ResourceTable> Build();
private:
@@ -97,7 +97,7 @@ class ValueBuilder {
template <typename... Args>
ValueBuilder& SetSource(Args&&... args) {
- value_->SetSource(Source{std::forward<Args>(args)...});
+ value_->SetSource(android::Source{std::forward<Args>(args)...});
return *this;
}
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index e029d025b366..eca0c1c12bab 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -21,8 +21,8 @@ using android::ConfigDescription;
namespace aapt {
namespace test {
-struct TestDiagnosticsImpl : public IDiagnostics {
- void Log(Level level, DiagMessageActual& actual_msg) override {
+struct TestDiagnosticsImpl : public android::IDiagnostics {
+ void Log(Level level, android::DiagMessageActual& actual_msg) override {
switch (level) {
case Level::Note:
return;
@@ -38,7 +38,7 @@ struct TestDiagnosticsImpl : public IDiagnostics {
}
};
-IDiagnostics* GetDiagnostics() {
+android::IDiagnostics* GetDiagnostics() {
static TestDiagnosticsImpl diag;
return &diag;
}
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 7006964d6f88..3f28361f6c2b 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -37,7 +37,7 @@
namespace aapt {
namespace test {
-IDiagnostics* GetDiagnostics();
+android::IDiagnostics* GetDiagnostics();
inline ResourceName ParseNameOrDie(const android::StringPiece& str) {
ResourceNameRef ref;
@@ -94,14 +94,14 @@ class TestFile : public io::IFile {
return OpenAsData();
}
- const Source& GetSource() const override {
+ const android::Source& GetSource() const override {
return source_;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestFile);
- Source source_;
+ android::Source source_;
};
} // namespace test
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index e1b8dd5687ff..4e4973ea39be 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -19,10 +19,10 @@
#include <list>
+#include "Diagnostics.h"
+#include "NameMangler.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
-
-#include "NameMangler.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
#include "test/Common.h"
@@ -43,7 +43,7 @@ class Context : public IAaptContext {
return &symbols_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index ddc1853ca13c..ff8b3683c577 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -16,16 +16,16 @@
#include "test/Fixture.h"
-#include <dirent.h>
-
#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/utf8.h>
#include <androidfw/StringPiece.h>
+#include <dirent.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "Diagnostics.h"
#include "cmd/Compile.h"
#include "cmd/Link.h"
#include "io/FileStream.h"
@@ -42,7 +42,8 @@ void ClearDirectory(const android::StringPiece& path) {
const std::string root_dir = path.to_string();
std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
if (!dir) {
- StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
+ StdErrDiagnostics().Error(android::DiagMessage()
+ << android::base::SystemErrorCodeToString(errno));
return;
}
@@ -90,13 +91,14 @@ void TestDirectoryFixture::WriteFile(const std::string& path, const std::string&
}
bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
- const android::StringPiece& out_dir, IDiagnostics* diag) {
+ const android::StringPiece& out_dir,
+ android::IDiagnostics* diag) {
WriteFile(path, contents);
CHECK(file::mkdirs(out_dir.data()));
return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
}
-bool CommandTestFixture::Link(const std::vector<std::string>& args, IDiagnostics* diag) {
+bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
@@ -112,7 +114,7 @@ bool CommandTestFixture::Link(const std::vector<std::string>& args, IDiagnostics
}
bool CommandTestFixture::Link(const std::vector<std::string>& args,
- const android::StringPiece& flat_dir, IDiagnostics* diag) {
+ const android::StringPiece& flat_dir, android::IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
@@ -210,7 +212,7 @@ LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
}
LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
if (auto files = file::FindFiles(dir, diag)) {
for (std::string& compile_file : files.value()) {
args_.emplace_back(file::BuildPath({dir, compile_file}));
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index f8c4889aee3b..61403b7b0a6d 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -73,15 +73,15 @@ class CommandTestFixture : public TestDirectoryFixture {
// Wries the contents of the file to the specified path. The file is compiled and the flattened
// file is written to the out directory.
bool CompileFile(const std::string& path, const std::string& contents,
- const android::StringPiece& flat_out_dir, IDiagnostics* diag);
+ const android::StringPiece& flat_out_dir, android::IDiagnostics* diag);
// Executes the link command with the specified arguments.
- bool Link(const std::vector<std::string>& args, IDiagnostics* diag);
+ bool Link(const std::vector<std::string>& args, android::IDiagnostics* diag);
// Executes the link command with the specified arguments. The flattened files residing in the
// flat directory will be added to the link command as file arguments.
bool Link(const std::vector<std::string>& args, const android::StringPiece& flat_dir,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Creates a minimal android manifest within the test directory and returns the file path.
std::string GetDefaultManifest(const char* package_name = kDefaultPackageName);
@@ -114,7 +114,7 @@ struct ManifestBuilder {
struct LinkCommandBuilder {
explicit LinkCommandBuilder(CommandTestFixture* fixture);
- LinkCommandBuilder& AddCompiledResDir(const std::string& dir, IDiagnostics* diag);
+ LinkCommandBuilder& AddCompiledResDir(const std::string& dir, android::IDiagnostics* diag);
LinkCommandBuilder& AddFlag(const std::string& flag);
LinkCommandBuilder& AddParameter(const std::string& param, const std::string& value);
LinkCommandBuilder& SetManifestFile(const std::string& manifest_path);
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 3285d8bafa4d..5d5b7cd7d472 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -333,9 +333,8 @@ bool FileFilter::operator()(const std::string& filename, FileType type) const {
if (ignore) {
if (chatty) {
- diag_->Warn(DiagMessage()
- << "skipping "
- << (type == FileType::kDirectory ? "dir '" : "file '")
+ diag_->Warn(android::DiagMessage()
+ << "skipping " << (type == FileType::kDirectory ? "dir '" : "file '")
<< filename << "' due to ignore pattern '" << token << "'");
}
return false;
@@ -345,11 +344,12 @@ bool FileFilter::operator()(const std::string& filename, FileType type) const {
}
std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
- IDiagnostics* diag, const FileFilter* filter) {
+ android::IDiagnostics* diag,
+ const FileFilter* filter) {
const std::string root_dir = path.to_string();
std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
if (!d) {
- diag->Error(DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir);
+ diag->Error(android::DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir);
return {};
}
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index a2b1b58e5d4f..ee95712f157d 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -24,12 +24,11 @@
#include <vector>
#include "android-base/macros.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
#include "utils/FileMap.h"
-#include "Diagnostics.h"
-#include "Source.h"
-
namespace aapt {
namespace file {
@@ -98,7 +97,8 @@ bool AppendSetArgsFromFile(const android::StringPiece& path,
// Pattern format is specified in the FileFilter::SetPattern() method.
class FileFilter {
public:
- explicit FileFilter(IDiagnostics* diag) : diag_(diag) {}
+ explicit FileFilter(android::IDiagnostics* diag) : diag_(diag) {
+ }
// Patterns syntax:
// - Delimiter is :
@@ -120,14 +120,14 @@ class FileFilter {
private:
DISALLOW_COPY_AND_ASSIGN(FileFilter);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
std::vector<std::string> pattern_tokens_;
};
// Returns a list of files relative to the directory identified by `path`.
// An optional FileFilter filters out any files that don't pass.
std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
- IDiagnostics* diag,
+ android::IDiagnostics* diag,
const FileFilter* filter = nullptr);
} // namespace file
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index efbbf8ebe013..9b7ebdd690ac 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -23,11 +23,12 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/StringPiece.h"
+#include "androidfw/Util.h"
#include "build/version.h"
#include "text/Unicode.h"
#include "text/Utf8Iterator.h"
-#include "util/BigBuffer.h"
#include "utils/Unicode.h"
using ::aapt::text::Utf8Iterator;
@@ -340,107 +341,6 @@ bool VerifyJavaStringFormat(const StringPiece& str) {
return true;
}
-std::string Utf8ToModifiedUtf8(const std::string& utf8) {
- // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
- // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
- // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
- // codepoints replaced with 2 3 byte surrogate pairs
- size_t modified_size = 0;
- const size_t size = utf8.size();
- for (size_t i = 0; i < size; i++) {
- if (((uint8_t) utf8[i] >> 4) == 0xF) {
- modified_size += 6;
- i += 3;
- } else {
- modified_size++;
- }
- }
-
- // Early out if no 4 byte codepoints are found
- if (size == modified_size) {
- return utf8;
- }
-
- std::string output;
- output.reserve(modified_size);
- for (size_t i = 0; i < size; i++) {
- if (((uint8_t) utf8[i] >> 4) == 0xF) {
- int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr);
-
- // Calculate the high and low surrogates as UTF-16 would
- int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
- int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
-
- // Encode each surrogate in UTF-8
- output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
- output.push_back((char) (0x80 | ((high >> 6) & 0x3F)));
- output.push_back((char) (0x80 | (high & 0x3F)));
- output.push_back((char) (0xE4 | ((low >> 12) & 0xF)));
- output.push_back((char) (0x80 | ((low >> 6) & 0x3F)));
- output.push_back((char) (0x80 | (low & 0x3F)));
- i += 3;
- } else {
- output.push_back(utf8[i]);
- }
- }
-
- return output;
-}
-
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
- // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
- // representation.
- std::string output;
- output.reserve(modified_utf8.size());
-
- size_t index = 0;
- const size_t modified_size = modified_utf8.size();
- while (index < modified_size) {
- size_t next_index;
- int32_t high_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, index,
- &next_index);
- if (high_surrogate < 0) {
- return {};
- }
-
- // Check that the first codepoint is within the high surrogate range
- if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) {
- int32_t low_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index,
- &next_index);
- if (low_surrogate < 0) {
- return {};
- }
-
- // Check that the second codepoint is within the low surrogate range
- if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) {
- const char32_t codepoint = (char32_t) (((high_surrogate - 0xD800) * 0x400)
- + (low_surrogate - 0xDC00) + 0x10000);
-
- // The decoded codepoint should represent a 4 byte, UTF-8 character
- const size_t utf8_length = (size_t) utf32_to_utf8_length(&codepoint, 1);
- if (utf8_length != 4) {
- return {};
- }
-
- // Encode the UTF-8 representation of the codepoint into the string
- char* start = &output[output.size()];
- output.resize(output.size() + utf8_length);
- utf32_to_utf8((char32_t*) &codepoint, 1, start, utf8_length + 1);
-
- index = next_index;
- continue;
- }
- }
-
- // Append non-surrogate pairs to the output string
- for (size_t i = index; i < next_index; i++) {
- output.push_back(modified_utf8[i]);
- }
- index = next_index;
- }
- return output;
-}
-
std::u16string Utf8ToUtf16(const StringPiece& utf8) {
ssize_t utf16_length = utf8_to_utf16_length(
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
@@ -467,7 +367,7 @@ std::string Utf16ToUtf8(const StringPiece16& utf16) {
return utf8;
}
-bool WriteAll(std::ostream& out, const BigBuffer& buffer) {
+bool WriteAll(std::ostream& out, const android::BigBuffer& buffer) {
for (const auto& b : buffer) {
if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) {
return false;
@@ -476,17 +376,6 @@ bool WriteAll(std::ostream& out, const BigBuffer& buffer) {
return true;
}
-std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer) {
- std::unique_ptr<uint8_t[]> data =
- std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
- uint8_t* p = data.get();
- for (const auto& block : buffer) {
- memcpy(p, block.buffer.get(), block.size);
- p += block.size;
- }
- return data;
-}
-
typename Tokenizer::iterator& Tokenizer::iterator::operator++() {
const char* start = token_.end();
const char* end = str_.end();
@@ -553,19 +442,5 @@ bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
return true;
}
-StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.stringAt(idx); str.ok()) {
- return *str;
- }
- return StringPiece16();
-}
-
-std::string GetString(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.string8At(idx); str.ok()) {
- return ModifiedUtf8ToUtf8(str->to_string());
- }
- return Utf16ToUtf8(GetString16(pool, idx));
-}
-
} // namespace util
} // namespace aapt
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index c3efe6a63feb..8d3b41315485 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -23,12 +23,11 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
#include "utils/ByteOrder.h"
-#include "util/BigBuffer.h"
-
#ifdef _WIN32
// TODO(adamlesinski): remove once http://b/32447322 is resolved.
// utils/ByteOrder.h includes winsock2.h on WIN32,
@@ -149,15 +148,6 @@ template <typename Container>
};
}
-// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
-// the conversion to UTF-16 happens within ResStringPool.
-android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
-
-// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
-// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
-// which maintains no state or cache. This means we must return an std::string copy.
-std::string GetString(const android::ResStringPool& pool, size_t idx);
-
// Checks that the Java string format contains no non-positional arguments (arguments without
// explicitly specifying an index) when there are more than one argument. This is an error
// because translations may rearrange the order of the arguments in the string, which will
@@ -212,19 +202,8 @@ inline StringBuilder::operator bool() const {
return error_.empty();
}
-// Converts a UTF8 string into Modified UTF8
-std::string Utf8ToModifiedUtf8(const std::string& utf8);
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
-
-// Converts a UTF8 string to a UTF16 string.
-std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
-std::string Utf16ToUtf8(const android::StringPiece16& utf16);
-
// Writes the entire BigBuffer to the output stream.
-bool WriteAll(std::ostream& out, const BigBuffer& buffer);
-
-// Copies the entire BigBuffer into a single buffer.
-std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);
+bool WriteAll(std::ostream& out, const android::BigBuffer& buffer);
// A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
// nor use standard containers.
@@ -277,22 +256,6 @@ inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
return Tokenizer(str, sep);
}
-inline uint16_t HostToDevice16(uint16_t value) {
- return htods(value);
-}
-
-inline uint32_t HostToDevice32(uint32_t value) {
- return htodl(value);
-}
-
-inline uint16_t DeviceToHost16(uint16_t value) {
- return dtohs(value);
-}
-
-inline uint32_t DeviceToHost32(uint32_t value) {
- return dtohl(value);
-}
-
// Given a path like: res/xml-sw600dp/foo.xml
//
// Extracts "res/xml-sw600dp/" into outPrefix.
@@ -305,13 +268,15 @@ bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPi
} // namespace util
+} // namespace aapt
+
+namespace std {
// Stream operator for functions. Calls the function with the stream as an argument.
// In the aapt namespace for lookup.
inline ::std::ostream& operator<<(::std::ostream& out,
const ::std::function<::std::ostream&(::std::ostream&)>& f) {
return f(out);
}
-
-} // namespace aapt
+} // namespace std
#endif // AAPT_UTIL_H
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index ea42d26358a8..9bdbd22b5697 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -22,17 +22,19 @@ namespace aapt {
namespace xml {
static bool wrapper_one(const XmlNodeAction::ActionFunc& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics*) {
+ const XmlActionExecutorPolicy& policy, android::SourcePathDiagnostics*) {
return f(el);
}
static bool wrapper_two(const XmlNodeAction::ActionFuncWithDiag& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics* diag) {
+ const XmlActionExecutorPolicy& policy,
+ android::SourcePathDiagnostics* diag) {
return f(el, diag);
}
static bool wrapper_three(const XmlNodeAction::ActionFuncWithPolicyAndDiag& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics* diag) {
+ const XmlActionExecutorPolicy& policy,
+ android::SourcePathDiagnostics* diag) {
return f(el, policy, diag);
}
@@ -51,7 +53,7 @@ void XmlNodeAction::Action(XmlNodeAction::ActionFuncWithPolicyAndDiag f) {
std::placeholders::_2, std::placeholders::_3));
}
-static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
+static void PrintElementToDiagMessage(const Element* el, android::DiagMessage* msg) {
*msg << "<";
if (!el->namespace_uri.empty()) {
*msg << el->namespace_uri << ":";
@@ -60,7 +62,7 @@ static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
}
bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
- SourcePathDiagnostics* diag, Element* el) const {
+ android::SourcePathDiagnostics* diag, Element* el) const {
bool error = false;
for (const ActionFuncWithPolicyAndDiag& action : actions_) {
error |= !action(el, policy, diag);
@@ -78,7 +80,7 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPi
}
if (policy != XmlActionExecutorPolicy::kNone) {
- DiagMessage error_msg(child_el->line_number);
+ android::DiagMessage error_msg(child_el->line_number);
error_msg << "unexpected element ";
PrintElementToDiagMessage(child_el, &error_msg);
error_msg << " found in ";
@@ -99,14 +101,14 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPi
return !error;
}
-bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
+bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, android::IDiagnostics* diag,
XmlResource* doc) const {
- SourcePathDiagnostics source_diag(doc->file.source, diag);
+ android::SourcePathDiagnostics source_diag(doc->file.source, diag);
Element* el = doc->root.get();
if (!el) {
if (policy == XmlActionExecutorPolicy::kAllowList) {
- source_diag.Error(DiagMessage() << "no root XML tag found");
+ source_diag.Error(android::DiagMessage() << "no root XML tag found");
return false;
}
return true;
@@ -121,7 +123,7 @@ bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* di
}
if (policy == XmlActionExecutorPolicy::kAllowList) {
- DiagMessage error_msg(el->line_number);
+ android::DiagMessage error_msg(el->line_number);
error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
source_diag.Error(error_msg);
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 78c43345deb7..8cc4573d2c45 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -23,8 +23,7 @@
#include <vector>
#include "android-base/macros.h"
-
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -50,8 +49,8 @@ enum class XmlActionExecutorPolicy {
class XmlNodeAction {
public:
using ActionFuncWithPolicyAndDiag =
- std::function<bool(Element*, XmlActionExecutorPolicy, SourcePathDiagnostics*)>;
- using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
+ std::function<bool(Element*, XmlActionExecutorPolicy, android::SourcePathDiagnostics*)>;
+ using ActionFuncWithDiag = std::function<bool(Element*, android::SourcePathDiagnostics*)>;
using ActionFunc = std::function<bool(Element*)>;
// Find or create a child XmlNodeAction that will be performed for the child element with the
@@ -69,7 +68,7 @@ class XmlNodeAction {
friend class XmlActionExecutor;
bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb,
- SourcePathDiagnostics* diag, Element* el) const;
+ android::SourcePathDiagnostics* diag, Element* el) const;
std::map<std::string, XmlNodeAction> map_;
std::vector<ActionFuncWithPolicyAndDiag> actions_;
@@ -88,7 +87,7 @@ class XmlActionExecutor {
// Execute the defined actions for this XmlResource.
// Returns true if all actions return true, otherwise returns false.
- bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
+ bool Execute(XmlActionExecutorPolicy policy, android::IDiagnostics* diag, XmlResource* doc) const;
private:
std::map<std::string, XmlNodeAction> map_;
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 8b7eadf9fac9..f51e8a47041d 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -183,7 +183,8 @@ static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
stack->pending_comment += comment;
}
-std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
+std::unique_ptr<XmlResource> Inflate(InputStream* in, android::IDiagnostics* diag,
+ const android::Source& source) {
Stack stack;
std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
@@ -199,28 +200,29 @@ std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const
size_t buffer_size = 0;
while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
- diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
<< XML_ErrorString(XML_GetErrorCode(parser.get())));
return {};
}
}
if (in->HadError()) {
- diag->Error(DiagMessage(source) << in->GetError());
+ diag->Error(android::DiagMessage(source) << in->GetError());
return {};
} else {
// Finish off the parsing.
if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
- diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
<< XML_ErrorString(XML_GetErrorCode(parser.get())));
return {};
}
}
return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
- StringPool{}, std::move(stack.root));
+ android::StringPool{}, std::move(stack.root));
}
-static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
+static void CopyAttributes(Element* el, android::ResXMLParser* parser,
+ android::StringPool* out_pool) {
const size_t attr_count = parser->getAttributeCount();
if (attr_count > 0) {
el->attributes.reserve(attr_count);
@@ -229,12 +231,12 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
size_t len;
const char16_t* str16 = parser->getAttributeNamespace(i, &len);
if (str16) {
- attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = parser->getAttributeName(i, &len);
if (str16) {
- attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
uint32_t res_id = parser->getAttributeNameResID(i);
@@ -244,7 +246,7 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
str16 = parser->getAttributeStringValue(i, &len);
if (str16) {
- attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.value = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
android::Res_value res_value;
@@ -294,12 +296,12 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getNamespacePrefix(&len);
if (str16) {
- decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.prefix = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getNamespaceUri(&len);
if (str16) {
- decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
if (pending_element == nullptr) {
@@ -323,12 +325,12 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getElementNamespace(&len);
if (str16) {
- el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getElementName(&len);
if (str16) {
- el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
Element* this_el = el.get();
@@ -349,7 +351,7 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getText(&len);
if (str16) {
- text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
+ text->text = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
CHECK(!node_stack.empty());
node_stack.top()->AppendChild(std::move(text));
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 5d31804d43b7..5bc55b6b68a1 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -21,11 +21,10 @@
#include <string>
#include <vector>
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
#include "Resource.h"
#include "ResourceValues.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "util/Util.h"
#include "xml/XmlUtil.h"
@@ -150,7 +149,7 @@ class XmlResource {
// StringPool must come before the xml::Node. Destructors are called in reverse order, and
// the xml::Node may have StringPool references that need to be destroyed before the StringPool
// is destroyed.
- StringPool string_pool;
+ android::StringPool string_pool;
std::unique_ptr<xml::Element> root;
@@ -158,7 +157,8 @@ class XmlResource {
};
// Inflates an XML DOM from an InputStream, logging errors to the logger.
-std::unique_ptr<XmlResource> Inflate(io::InputStream* in, IDiagnostics* diag, const Source& source);
+std::unique_ptr<XmlResource> Inflate(io::InputStream* in, android::IDiagnostics* diag,
+ const android::Source& source);
// Inflates an XML DOM from a binary ResXMLTree.
std::unique_ptr<XmlResource> Inflate(const void* data, size_t len,
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 6c717dcd84c8..c50333894099 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -45,7 +45,7 @@ TEST(XmlDomTest, Inflate) {
StdErrDiagnostics diag;
StringInputStream in(input);
- std::unique_ptr<XmlResource> doc = Inflate(&in, &diag, Source("test.xml"));
+ std::unique_ptr<XmlResource> doc = Inflate(&in, &diag, android::Source("test.xml"));
ASSERT_THAT(doc, NotNull());
Element* el = doc->root.get();
@@ -77,13 +77,13 @@ TEST(XmlDomTest, BinaryInflate) {
decl.line_number = 2u;
doc->root->namespace_decls.push_back(decl);
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
XmlFlattenerOptions options;
options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
- auto block = util::Copy(buffer);
+ auto block = android::util::Copy(buffer);
std::unique_ptr<XmlResource> new_doc = Inflate(block.get(), buffer.size(), nullptr);
ASSERT_THAT(new_doc, NotNull());
diff --git a/tools/bit/adb.cpp b/tools/bit/adb.cpp
index f521a63255e1..201028ba900a 100644
--- a/tools/bit/adb.cpp
+++ b/tools/bit/adb.cpp
@@ -73,7 +73,7 @@ string
get_system_property(const string& name, int* err)
{
Command cmd("adb");
- cmd.AddArg("shell");
+ cmd.AddArg("exec-out");
cmd.AddArg("getprop");
cmd.AddArg(name);
@@ -278,7 +278,7 @@ run_instrumentation_test(const string& packageName, const string& runner, const
InstrumentationCallbacks* callbacks)
{
Command cmd("adb");
- cmd.AddArg("shell");
+ cmd.AddArg("exec-out");
cmd.AddArg("am");
cmd.AddArg("instrument");
cmd.AddArg("-w");
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index fd184f50091a..0d48070fd0c6 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -52,24 +52,22 @@ struct Target {
int testPassCount;
int testFailCount;
+ int testIgnoreCount;
int unknownFailureCount; // unknown failure == "Process crashed", etc.
- bool actionsWithNoTests;
Target(bool b, bool i, bool t, const string& p);
};
Target::Target(bool b, bool i, bool t, const string& p)
- :build(b),
- install(i),
- test(t),
- pattern(p),
- testActionCount(0),
- testPassCount(0),
- testFailCount(0),
- unknownFailureCount(0),
- actionsWithNoTests(false)
-{
-}
+ : build(b),
+ install(i),
+ test(t),
+ pattern(p),
+ testActionCount(0),
+ testPassCount(0),
+ testFailCount(0),
+ testIgnoreCount(0),
+ unknownFailureCount(0) {}
/**
* Command line options.
@@ -188,13 +186,12 @@ struct TestAction {
// The number of tests that failed
int failCount;
+
+ // The number of tests that were ignored (because of @Ignore)
+ int ignoreCount;
};
-TestAction::TestAction()
- :passCount(0),
- failCount(0)
-{
-}
+TestAction::TestAction() : passCount(0), failCount(0), ignoreCount(0) {}
/**
* Record for an activity that is going to be launched.
@@ -278,7 +275,7 @@ TestResults::OnTestStatus(TestStatus& status)
line << " of " << testCount;
}
}
- line << ": " << m_currentAction->target->name << ':' << className << "\\#" << testName;
+ line << ": " << m_currentAction->target->name << ':' << className << "#" << testName;
print_one_line("%s", line.str().c_str());
} else if ((resultCode == -1) || (resultCode == -2)) {
// test failed
@@ -286,9 +283,9 @@ TestResults::OnTestStatus(TestStatus& status)
// all as "failures".
m_currentAction->failCount++;
m_currentAction->target->testFailCount++;
- printf("%s\n%sFailed: %s:%s\\#%s%s\n", g_escapeClearLine, g_escapeRedBold,
- m_currentAction->target->name.c_str(), className.c_str(),
- testName.c_str(), g_escapeEndColor);
+ printf("%s\n%sFailed: %s:%s#%s%s\n", g_escapeClearLine, g_escapeRedBold,
+ m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
+ g_escapeEndColor);
bool stackFound;
string stack = get_bundle_string(results, &stackFound, "stack", NULL);
@@ -300,6 +297,13 @@ TestResults::OnTestStatus(TestStatus& status)
} else if (stackFound) {
printf("%s\n", stack.c_str());
}
+ } else if (resultCode == -3) {
+ // test ignored
+ m_currentAction->ignoreCount++;
+ m_currentAction->target->testIgnoreCount++;
+ printf("%s\n%sIgnored: %s:%s#%s%s\n", g_escapeClearLine, g_escapeYellowBold,
+ m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
+ g_escapeEndColor);
}
}
@@ -403,11 +407,14 @@ print_usage(FILE* out) {
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs all the\n");
fprintf(out, " tests in the ProtoOutputStreamBoolTest class.\n");
fprintf(out, "\n");
- fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite\n");
+ fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite\n");
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
fprintf(out, " test method on that class.\n");
fprintf(out, "\n");
- fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite,.ProtoOutputStreamBoolTest\\#testRepeated\n");
+ fprintf(out,
+ " bit "
+ "CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite,.ProtoOutputStreamBoolTest#"
+ "testRepeated\n");
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
fprintf(out, " and testRepeated test methods on that class.\n");
fprintf(out, "\n");
@@ -450,6 +457,35 @@ print_usage(FILE* out) {
fprintf(out, "\n");
}
+/**
+ * Prints a possibly color-coded summary of test results. Example output:
+ *
+ * "34 passed, 0 failed, 1 ignored\n"
+ */
+static void print_results(int passed, int failed, int ignored) {
+ char const* nothing = "";
+ char const* cp = nothing;
+ char const* cf = nothing;
+ char const* ci = nothing;
+
+ if (failed > 0) {
+ cf = g_escapeRedBold;
+ } else if (passed > 0 || ignored > 0) {
+ cp = passed > 0 ? g_escapeGreenBold : nothing;
+ ci = ignored > 0 ? g_escapeYellowBold : nothing;
+ } else {
+ cp = g_escapeYellowBold;
+ cf = g_escapeYellowBold;
+ }
+
+ if (ignored > 0) {
+ printf("%s%d passed%s, %s%d failed%s, %s%d ignored%s\n", cp, passed, g_escapeEndColor, cf,
+ failed, g_escapeEndColor, ci, ignored, g_escapeEndColor);
+ } else {
+ printf("%s%d passed%s, %s%d failed%s\n", cp, passed, g_escapeEndColor, cf, failed,
+ g_escapeEndColor);
+ }
+}
/**
* Sets the appropriate flag* variables. If there is a problem with the
@@ -812,7 +848,7 @@ run_phases(vector<Target*> targets, const Options& options)
// Stop & Sync
if (!options.noRestart) {
- err = run_adb("shell", "stop", NULL);
+ err = run_adb("exec-out", "stop", NULL);
check_error(err);
}
err = run_adb("remount", NULL);
@@ -831,9 +867,9 @@ run_phases(vector<Target*> targets, const Options& options)
} else {
print_status("Restarting the runtime");
- err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
+ err = run_adb("exec-out", "setprop", "sys.boot_completed", "0", NULL);
check_error(err);
- err = run_adb("shell", "start", NULL);
+ err = run_adb("exec-out", "start", NULL);
check_error(err);
}
@@ -846,7 +882,7 @@ run_phases(vector<Target*> targets, const Options& options)
sleep(2);
}
sleep(1);
- err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
+ err = run_adb("exec-out", "wm", "dismiss-keyguard", NULL);
check_error(err);
}
}
@@ -863,7 +899,7 @@ run_phases(vector<Target*> targets, const Options& options)
continue;
}
// TODO: if (!apk.file.fileInfo.exists || apk.file.HasChanged())
- err = run_adb("shell", "mkdir", "-p", dir.c_str(), NULL);
+ err = run_adb("exec-out", "mkdir", "-p", dir.c_str(), NULL);
check_error(err);
err = run_adb("push", pushed.file.filename.c_str(), pushed.dest.c_str(), NULL);
check_error(err);
@@ -945,9 +981,9 @@ run_phases(vector<Target*> targets, const Options& options)
}
}
if (runAll) {
- err = run_adb("shell", installedPath.c_str(), NULL);
+ err = run_adb("exec-out", installedPath.c_str(), NULL);
} else {
- err = run_adb("shell", installedPath.c_str(), filterArg.c_str(), NULL);
+ err = run_adb("exec-out", installedPath.c_str(), filterArg.c_str(), NULL);
}
if (err == 0) {
target->testPassCount++;
@@ -1035,22 +1071,10 @@ run_phases(vector<Target*> targets, const Options& options)
err = run_instrumentation_test(action.packageName, action.runner, action.className,
&testResults);
check_error(err);
- if (action.passCount == 0 && action.failCount == 0) {
- action.target->actionsWithNoTests = true;
- }
int total = action.passCount + action.failCount;
printf("%sRan %d test%s for %s. ", g_escapeClearLine,
total, total > 1 ? "s" : "", action.target->name.c_str());
- if (action.passCount == 0 && action.failCount == 0) {
- printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
- action.failCount, g_escapeEndColor);
- } else if (action.failCount > 0) {
- printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
- action.failCount, g_escapeEndColor);
- } else {
- printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
- g_escapeEndColor, action.failCount);
- }
+ print_results(action.passCount, action.failCount, action.ignoreCount);
if (!testResults.IsSuccess()) {
printf("\n%sTest didn't finish successfully: %s%s\n", g_escapeRedBold,
testResults.GetErrorMessage().c_str(), g_escapeEndColor);
@@ -1073,7 +1097,7 @@ run_phases(vector<Target*> targets, const Options& options)
const ActivityAction& action = activityActions[0];
string componentName = action.packageName + "/" + action.className;
- err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
+ err = run_adb("exec-out", "am", "start", componentName.c_str(), NULL);
check_error(err);
}
@@ -1147,17 +1171,11 @@ run_phases(vector<Target*> targets, const Options& options)
printf(" %sUnknown failure, see above message.%s\n",
g_escapeRedBold, g_escapeEndColor);
hasErrors = true;
- } else if (target->actionsWithNoTests) {
- printf(" %s%d passed, %d failed%s\n", g_escapeYellowBold,
- target->testPassCount, target->testFailCount, g_escapeEndColor);
- hasErrors = true;
- } else if (target->testFailCount > 0) {
- printf(" %d passed, %s%d failed%s\n", target->testPassCount,
- g_escapeRedBold, target->testFailCount, g_escapeEndColor);
- hasErrors = true;
} else {
- printf(" %s%d passed%s, %d failed\n", g_escapeGreenBold,
- target->testPassCount, g_escapeEndColor, target->testFailCount);
+ printf(" %s%s ", target->name.c_str(),
+ padding.c_str() + target->name.length());
+ print_results(target->testPassCount, target->testFailCount,
+ target->testIgnoreCount);
}
}
}
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 5fc800b09ee9..685733386cae 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -393,7 +393,7 @@ private fun ClassPrinter.generateBuilderBuild() {
fun ClassPrinter.generateParcelable() {
val booleanFields = fields.filter { it.Type == "boolean" }
val objectFields = fields.filter { it.Type !in PRIMITIVE_TYPES }
- val nullableFields = objectFields.filter { it.mayBeNull }
+ val nullableFields = objectFields.filter { it.mayBeNull && it.Type !in PRIMITIVE_ARRAY_TYPES }
val nonBooleanFields = fields - booleanFields
@@ -457,7 +457,7 @@ fun ClassPrinter.generateParcelable() {
hasAnnotation("@$DataClassEnum") ->
+"dest.writeInt($internalGetter == null ? -1 : $internalGetter.ordinal());"
else -> {
- if (mayBeNull) !"if ($internalGetter != null) "
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) !"if ($internalGetter != null) "
var args = internalGetter
if (ParcelMethodsSuffix.startsWith("Parcelable")
|| ParcelMethodsSuffix.startsWith("TypedObject")
@@ -529,7 +529,7 @@ fun ClassPrinter.generateParcelable() {
if (passContainer) {
methodArgs.add(_name)
!"$Type $_name = "
- if (mayBeNull) {
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
+"null;"
!"if ((flg & $fieldBit) != 0) {"
pushIndent()
@@ -539,7 +539,9 @@ fun ClassPrinter.generateParcelable() {
+"$containerInitExpr;"
} else {
!"$Type $_name = "
- if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : "
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
+ !"(flg & $fieldBit) == 0 ? null : "
+ }
if (ParcelMethodsSuffix == "StrongInterface") {
!"$FieldClass.Stub.asInterface("
} else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" &&
@@ -578,7 +580,7 @@ fun ClassPrinter.generateParcelable() {
+";"
// Cleanup if passContainer
- if (passContainer && mayBeNull) {
+ if (passContainer && mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
popIndent()
rmEmptyLine()
+"\n}"
@@ -949,4 +951,4 @@ fun ClassPrinter.generateMetadata(file: File) {
+""
+"@Deprecated"
+"private void __metadata() {}\n"
-} \ No newline at end of file
+}
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index 4b508d022991..bcc6230fd53f 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -10,6 +10,7 @@ const val GENERATED_END = "// End of generated code"
const val INDENT_SINGLE = " "
val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
+val PRIMITIVE_ARRAY_TYPES = listOf("byte[]", "short[]", "int[]", "long[]", "char[]", "float[]", "double[]", "boolean[]")
val BOXED_PRIMITIVE_TYPES = PRIMITIVE_TYPES.map { it.capitalize() } - "Int" + "Integer" - "Char" + "Character"
val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern")
@@ -133,4 +134,4 @@ private fun handleUpdateFlag(cliArgs: Array<String>, sourceLines: List<String>):
System.exit(0)
}
return cliArgs - "--update-only"
-} \ No newline at end of file
+}
diff --git a/tools/lint/README.md b/tools/lint/README.md
index b534b62cb395..c674d36431b7 100644
--- a/tools/lint/README.md
+++ b/tools/lint/README.md
@@ -78,6 +78,7 @@ adding `cmd.Flag("--nowarn")` and running lint again.
## Documentation
- [Android Lint Docs](https://googlesamples.github.io/android-custom-lint-rules/)
+- [Lint Check Unit Testing](https://googlesamples.github.io/android-custom-lint-rules/api-guide/unit-testing.md.html)
- [Android Lint source files](https://source.corp.google.com/studio-main/tools/base/lint/libs/lint-api/src/main/java/com/android/tools/lint/)
- [PSI source files](https://github.com/JetBrains/intellij-community/tree/master/java/java-psi-api/src/com/intellij/psi)
- [UAST source files](https://upsource.jetbrains.com/idea-ce/structure/idea-ce-7b9b8cc138bbd90aec26433f82cd2c6838694003/uast/uast-common/src/org/jetbrains/uast)
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index a6fd9bba6192..d19f4cceeaaf 100644
--- a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -19,21 +19,25 @@ package com.google.android.lint
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.android.lint.parcel.SaferParcelChecker
import com.google.auto.service.AutoService
@AutoService(IssueRegistry::class)
@Suppress("UnstableApiUsage")
class AndroidFrameworkIssueRegistry : IssueRegistry() {
override val issues = listOf(
- CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
- CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
- CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
- CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
- CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
- CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
- CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
- EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
- EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION
+ CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
+ CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
+ CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+ CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+ CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+ CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+ CallingIdentityTokenDetector.ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE,
+ CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
+ EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
+ EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
+ SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
+ PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS
)
override val api: Int
@@ -43,8 +47,8 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() {
get() = 8
override val vendor: Vendor = Vendor(
- vendorName = "Android",
- feedbackUrl = "http://b/issues/new?component=315013",
- contact = "brufino@google.com"
+ vendorName = "Android",
+ feedbackUrl = "http://b/issues/new?component=315013",
+ contact = "brufino@google.com"
)
}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
index 930378b168b2..0c375c358e61 100644
--- a/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
@@ -33,6 +33,7 @@ import org.jetbrains.uast.UBlockExpression
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UDeclarationsExpression
import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UIfExpression
import org.jetbrains.uast.ULocalVariable
import org.jetbrains.uast.USimpleNameReferenceExpression
import org.jetbrains.uast.UTryExpression
@@ -52,10 +53,10 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
private val tokensMap = mutableMapOf<String, Token>()
override fun getApplicableUastTypes(): List<Class<out UElement?>> =
- listOf(ULocalVariable::class.java, UCallExpression::class.java)
+ listOf(ULocalVariable::class.java, UCallExpression::class.java)
override fun createUastHandler(context: JavaContext): UElementHandler =
- TokenUastHandler(context)
+ TokenUastHandler(context)
/** File analysis starts with a clear map */
override fun beforeCheckFile(context: Context) {
@@ -70,9 +71,9 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
override fun afterCheckFile(context: Context) {
for (token in tokensMap.values) {
context.report(
- ISSUE_UNUSED_TOKEN,
- token.location,
- getIncidentMessageUnusedToken(token.variableName)
+ ISSUE_UNUSED_TOKEN,
+ token.location,
+ getIncidentMessageUnusedToken(token.variableName)
)
}
tokensMap.clear()
@@ -96,9 +97,9 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
val variableName = node.getName()
if (!node.isFinal) {
context.report(
- ISSUE_NON_FINAL_TOKEN,
- location,
- getIncidentMessageNonFinalToken(variableName)
+ ISSUE_NON_FINAL_TOKEN,
+ location,
+ getIncidentMessageNonFinalToken(variableName)
)
}
// If there exists an unused variable with the same name in the map, we can imply that
@@ -106,9 +107,9 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
val oldToken = tokensMap[variableName]
if (oldToken != null) {
context.report(
- ISSUE_UNUSED_TOKEN,
- oldToken.location,
- getIncidentMessageUnusedToken(oldToken.variableName)
+ ISSUE_UNUSED_TOKEN,
+ oldToken.location,
+ getIncidentMessageUnusedToken(oldToken.variableName)
)
}
// If there exists a token in the same scope as the current new token, it means that
@@ -117,56 +118,84 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
val firstCallToken = findFirstTokenInScope(node)
if (firstCallToken != null) {
context.report(
- ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
- createNestedLocation(firstCallToken, location),
- getIncidentMessageNestedClearIdentityCallsPrimary(
- firstCallToken.variableName,
- variableName
- )
+ ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+ createNestedLocation(firstCallToken, location),
+ getIncidentMessageNestedClearIdentityCallsPrimary(
+ firstCallToken.variableName,
+ variableName
+ )
)
}
// If the next statement in the tree is not a try-finally statement, we need to report
// the "clearCallingIdentity() is not followed by try-finally" issue
val finallyClause = (getNextStatementOfLocalVariable(node) as? UTryExpression)
- ?.finallyClause
+ ?.finallyClause
if (finallyClause == null) {
context.report(
- ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
- location,
- getIncidentMessageClearIdentityCallNotFollowedByTryFinally(variableName)
+ ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+ location,
+ getIncidentMessageClearIdentityCallNotFollowedByTryFinally(variableName)
)
}
tokensMap[variableName] = Token(
- variableName,
- node.sourcePsi?.getUseScope(),
- location,
- finallyClause
+ variableName,
+ node.sourcePsi?.getUseScope(),
+ location,
+ finallyClause
)
}
- /**
- * For every method():
- * - Checks use of caller-aware methods issue
- * For every call of Binder.restoreCallingIdentity(token):
- * - Checks for restoreCallingIdentity() not in the finally block issue
- * - Removes token from tokensMap if token is within the scope of the method
- */
override fun visitCallExpression(node: UCallExpression) {
+ when {
+ isMethodCall(node, Method.BINDER_CLEAR_CALLING_IDENTITY) -> {
+ checkClearCallingIdentityCall(node)
+ }
+ isMethodCall(node, Method.BINDER_RESTORE_CALLING_IDENTITY) -> {
+ checkRestoreCallingIdentityCall(node)
+ }
+ isCallerAwareMethod(node) -> checkCallerAwareMethod(node)
+ }
+ }
+
+ private fun checkClearCallingIdentityCall(node: UCallExpression) {
+ var firstNonQualifiedParent = getFirstNonQualifiedParent(node)
+ // if the call expression is inside a ternary, and the ternary is assigned
+ // to a variable, then we are still technically assigning
+ // any result of clearCallingIdentity to a variable
+ if (firstNonQualifiedParent is UIfExpression && firstNonQualifiedParent.isTernary) {
+ firstNonQualifiedParent = firstNonQualifiedParent.uastParent
+ }
+ if (firstNonQualifiedParent !is ULocalVariable) {
+ context.report(
+ ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE,
+ context.getLocation(node),
+ getIncidentMessageResultOfClearIdentityCallNotStoredInVariable(
+ node.getQualifiedParentOrThis().asRenderString()
+ )
+ )
+ }
+ }
+
+ private fun checkCallerAwareMethod(node: UCallExpression) {
val token = findFirstTokenInScope(node)
- if (isCallerAwareMethod(node) && token != null) {
+ if (token != null) {
context.report(
- ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
- context.getLocation(node),
- getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
- token.variableName,
- node.asRenderString()
- )
+ ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+ context.getLocation(node),
+ getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
+ token.variableName,
+ node.asRenderString()
+ )
)
- return
}
- if (!isMethodCall(node, Method.BINDER_RESTORE_CALLING_IDENTITY)) return
- val first = node.valueArguments[0].skipParenthesizedExprDown()
- val arg = first as? USimpleNameReferenceExpression ?: return
+ }
+
+ /**
+ * - Checks for restoreCallingIdentity() not in the finally block issue
+ * - Removes token from tokensMap if token is within the scope of the method
+ */
+ private fun checkRestoreCallingIdentityCall(node: UCallExpression) {
+ val arg = node.valueArguments[0] as? USimpleNameReferenceExpression ?: return
val variableName = arg.identifier
val originalScope = tokensMap[variableName]?.scope ?: return
val psi = arg.sourcePsi ?: return
@@ -174,26 +203,31 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
// token declaration. If not within the scope, no action is needed because the token is
// irrelevant i.e. not in the same scope or was not declared with clearCallingIdentity()
if (!PsiSearchScopeUtil.isInScope(originalScope, psi)) return
- // - We do not report "restore identity call not in finally" issue when there is no
+ // We do not report "restore identity call not in finally" issue when there is no
// finally block because that case is already handled by "clear identity call not
// followed by try-finally" issue
- // - UCallExpression can be a child of UQualifiedReferenceExpression, i.e.
- // receiver.selector, so to get the call's immediate parent we need to get the topmost
- // parent qualified reference expression and access its parent
if (tokensMap[variableName]?.finallyBlock != null &&
- skipParenthesizedExprUp(node.getQualifiedParentOrThis().uastParent) !=
- tokensMap[variableName]?.finallyBlock) {
+ getFirstNonQualifiedParent(node) !=
+ tokensMap[variableName]?.finallyBlock
+ ) {
context.report(
- ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
- context.getLocation(node),
- getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName)
+ ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+ context.getLocation(node),
+ getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName)
)
}
tokensMap.remove(variableName)
}
+ private fun getFirstNonQualifiedParent(expression: UCallExpression): UElement? {
+ // UCallExpression can be a child of UQualifiedReferenceExpression, i.e.
+ // receiver.selector, so to get the call's immediate parent we need to get the topmost
+ // parent qualified reference expression and access its parent
+ return skipParenthesizedExprUp(expression.getQualifiedParentOrThis().uastParent)
+ }
+
private fun isCallerAwareMethod(expression: UCallExpression): Boolean =
- callerAwareMethods.any { method -> isMethodCall(expression, method) }
+ callerAwareMethods.any { method -> isMethodCall(expression, method) }
private fun isMethodCall(
expression: UCallExpression,
@@ -201,12 +235,12 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
): Boolean {
val psiMethod = expression.resolve() ?: return false
return psiMethod.getName() == method.methodName &&
- context.evaluator.methodMatches(
- psiMethod,
- method.className,
- /* allowInherit */ true,
- *method.args
- )
+ context.evaluator.methodMatches(
+ psiMethod,
+ method.className,
+ /* allowInherit */ true,
+ *method.args
+ )
}
/**
@@ -255,7 +289,7 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
return declarations[indexInDeclarations + 1]
}
val enclosingBlock = node
- .getParentOfType<UBlockExpression>(strict = true) ?: return null
+ .getParentOfType<UBlockExpression>(strict = true) ?: return null
val expressions = enclosingBlock.expressions
val indexInBlock = expressions.indexOf(declarationsExpression as UElement)
return if (indexInBlock == -1) null else expressions.getOrNull(indexInBlock + 1)
@@ -301,12 +335,12 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
secondCallTokenLocation: Location
): Location {
return cloneLocation(secondCallTokenLocation)
- .withSecondary(
- cloneLocation(firstCallToken.location),
- getIncidentMessageNestedClearIdentityCallsSecondary(
- firstCallToken.variableName
- )
+ .withSecondary(
+ cloneLocation(firstCallToken.location),
+ getIncidentMessageNestedClearIdentityCallsSecondary(
+ firstCallToken.variableName
)
+ )
}
private fun cloneLocation(location: Location): Location {
@@ -347,20 +381,20 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
const val CLASS_USER_HANDLE = "android.os.UserHandle"
private val callerAwareMethods = listOf(
- Method.BINDER_GET_CALLING_PID,
- Method.BINDER_GET_CALLING_UID,
- Method.BINDER_GET_CALLING_UID_OR_THROW,
- Method.BINDER_GET_CALLING_USER_HANDLE,
- Method.USER_HANDLE_GET_CALLING_APP_ID,
- Method.USER_HANDLE_GET_CALLING_USER_ID
+ Method.BINDER_GET_CALLING_PID,
+ Method.BINDER_GET_CALLING_UID,
+ Method.BINDER_GET_CALLING_UID_OR_THROW,
+ Method.BINDER_GET_CALLING_USER_HANDLE,
+ Method.USER_HANDLE_GET_CALLING_APP_ID,
+ Method.USER_HANDLE_GET_CALLING_USER_ID
)
/** Issue: unused token from Binder.clearCallingIdentity() */
@JvmField
val ISSUE_UNUSED_TOKEN: Issue = Issue.create(
- id = "UnusedTokenOfOriginalCallingIdentity",
- briefDescription = "Unused token of Binder.clearCallingIdentity()",
- explanation = """
+ id = "UnusedTokenOfOriginalCallingIdentity",
+ briefDescription = "Unused token of Binder.clearCallingIdentity()",
+ explanation = """
You cleared the original calling identity with \
`Binder.clearCallingIdentity()`, but have not used the returned token to \
restore the identity.
@@ -370,26 +404,26 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
`token` is the result of `Binder.clearCallingIdentity()`
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageUnusedToken(variableName: String) = "`$variableName` has " +
- "not been used to restore the calling identity. Introduce a `try`-`finally` " +
- "after the declaration and call `Binder.restoreCallingIdentity($variableName)` " +
- "in `finally` or remove `$variableName`."
+ "not been used to restore the calling identity. Introduce a `try`-`finally` " +
+ "after the declaration and call `Binder.restoreCallingIdentity($variableName)` " +
+ "in `finally` or remove `$variableName`."
/** Issue: non-final token from Binder.clearCallingIdentity() */
@JvmField
val ISSUE_NON_FINAL_TOKEN: Issue = Issue.create(
- id = "NonFinalTokenOfOriginalCallingIdentity",
- briefDescription = "Non-final token of Binder.clearCallingIdentity()",
- explanation = """
+ id = "NonFinalTokenOfOriginalCallingIdentity",
+ briefDescription = "Non-final token of Binder.clearCallingIdentity()",
+ explanation = """
You cleared the original calling identity with \
`Binder.clearCallingIdentity()`, but have not made the returned token `final`.
@@ -397,47 +431,47 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
which can cause problems when restoring the identity with \
`Binder.restoreCallingIdentity(token)`.
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageNonFinalToken(variableName: String) = "`$variableName` is " +
- "a non-final token from `Binder.clearCallingIdentity()`. Add `final` keyword to " +
- "`$variableName`."
+ "a non-final token from `Binder.clearCallingIdentity()`. Add `final` keyword to " +
+ "`$variableName`."
/** Issue: nested calls of Binder.clearCallingIdentity() */
@JvmField
val ISSUE_NESTED_CLEAR_IDENTITY_CALLS: Issue = Issue.create(
- id = "NestedClearCallingIdentityCalls",
- briefDescription = "Nested calls of Binder.clearCallingIdentity()",
- explanation = """
+ id = "NestedClearCallingIdentityCalls",
+ briefDescription = "Nested calls of Binder.clearCallingIdentity()",
+ explanation = """
You cleared the original calling identity with \
`Binder.clearCallingIdentity()` twice without restoring identity with the \
result of the first call.
Make sure to restore the identity after each clear identity call.
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageNestedClearIdentityCallsPrimary(
firstCallVariableName: String,
secondCallVariableName: String
): String = "The calling identity has already been cleared and returned into " +
- "`$firstCallVariableName`. Move `$secondCallVariableName` declaration after " +
- "restoring the calling identity with " +
- "`Binder.restoreCallingIdentity($firstCallVariableName)`."
+ "`$firstCallVariableName`. Move `$secondCallVariableName` declaration after " +
+ "restoring the calling identity with " +
+ "`Binder.restoreCallingIdentity($firstCallVariableName)`."
private fun getIncidentMessageNestedClearIdentityCallsSecondary(
firstCallVariableName: String
@@ -446,10 +480,10 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
/** Issue: Binder.clearCallingIdentity() is not followed by `try-finally` statement */
@JvmField
val ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY: Issue = Issue.create(
- id = "ClearIdentityCallNotFollowedByTryFinally",
- briefDescription = "Binder.clearCallingIdentity() is not followed by try-finally " +
- "statement",
- explanation = """
+ id = "ClearIdentityCallNotFollowedByTryFinally",
+ briefDescription = "Binder.clearCallingIdentity() is not followed by try-finally " +
+ "statement",
+ explanation = """
You cleared the original calling identity with \
`Binder.clearCallingIdentity()`, but the next statement is not a `try` \
statement.
@@ -472,30 +506,30 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
code with your identity that was originally intended to run with the calling \
application's identity.
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageClearIdentityCallNotFollowedByTryFinally(
variableName: String
): String = "You cleared the calling identity and returned the result into " +
- "`$variableName`, but the next statement is not a `try`-`finally` statement. " +
- "Define a `try`-`finally` block after `$variableName` declaration to ensure a " +
- "safe restore of the calling identity by calling " +
- "`Binder.restoreCallingIdentity($variableName)` and making it an immediate child " +
- "of the `finally` block."
+ "`$variableName`, but the next statement is not a `try`-`finally` statement. " +
+ "Define a `try`-`finally` block after `$variableName` declaration to ensure a " +
+ "safe restore of the calling identity by calling " +
+ "`Binder.restoreCallingIdentity($variableName)` and making it an immediate child " +
+ "of the `finally` block."
/** Issue: Binder.restoreCallingIdentity() is not in finally block */
@JvmField
val ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK: Issue = Issue.create(
- id = "RestoreIdentityCallNotInFinallyBlock",
- briefDescription = "Binder.restoreCallingIdentity() is not in finally block",
- explanation = """
+ id = "RestoreIdentityCallNotInFinallyBlock",
+ briefDescription = "Binder.restoreCallingIdentity() is not in finally block",
+ explanation = """
You are restoring the original calling identity with \
`Binder.restoreCallingIdentity()`, but the call is not an immediate child of \
the `finally` block of the `try` statement.
@@ -516,28 +550,28 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
`finally` block, you may run code with your identity that was originally \
intended to run with the calling application's identity.
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageRestoreIdentityCallNotInFinallyBlock(
variableName: String
): String = "`Binder.restoreCallingIdentity($variableName)` is not an immediate child of " +
- "the `finally` block of the try statement after `$variableName` declaration. " +
- "Surround the call with `finally` block and call it unconditionally."
+ "the `finally` block of the try statement after `$variableName` declaration. " +
+ "Surround the call with `finally` block and call it unconditionally."
/** Issue: Use of caller-aware methods after Binder.clearCallingIdentity() */
@JvmField
val ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY: Issue = Issue.create(
- id = "UseOfCallerAwareMethodsWithClearedIdentity",
- briefDescription = "Use of caller-aware methods after " +
- "Binder.clearCallingIdentity()",
- explanation = """
+ id = "UseOfCallerAwareMethodsWithClearedIdentity",
+ briefDescription = "Use of caller-aware methods after " +
+ "Binder.clearCallingIdentity()",
+ explanation = """
You cleared the original calling identity with \
`Binder.clearCallingIdentity()`, but used one of the methods below before \
restoring the identity. These methods will use your own identity instead of \
@@ -556,22 +590,59 @@ class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
UserHandle.getCallingUserId()
```
""",
- category = Category.SECURITY,
- priority = 6,
- severity = Severity.WARNING,
- implementation = Implementation(
- CallingIdentityTokenDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
)
private fun getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
variableName: String,
methodName: String
): String = "You cleared the original identity with `Binder.clearCallingIdentity()` " +
- "and returned into `$variableName`, so `$methodName` will be using your own " +
- "identity instead of the caller's. Either explicitly query your own identity or " +
- "move it after restoring the identity with " +
- "`Binder.restoreCallingIdentity($variableName)`."
+ "and returned into `$variableName`, so `$methodName` will be using your own " +
+ "identity instead of the caller's. Either explicitly query your own identity or " +
+ "move it after restoring the identity with " +
+ "`Binder.restoreCallingIdentity($variableName)`."
+
+ /** Issue: Result of Binder.clearCallingIdentity() is not stored in a variable */
+ @JvmField
+ val ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE: Issue = Issue.create(
+ id = "ResultOfClearIdentityCallNotStoredInVariable",
+ briefDescription = "Result of Binder.clearCallingIdentity() is not stored in a " +
+ "variable",
+ explanation = """
+ You cleared the original calling identity with \
+ `Binder.clearCallingIdentity()`, but did not store the result of the method \
+ call in a variable. You need to store the result in a variable and restore it later.
+
+ Use the following pattern for running operations with your own identity:
+
+ ```
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Code using your own identity
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ ```
+ """,
+ category = Category.SECURITY,
+ priority = 6,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ CallingIdentityTokenDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private fun getIncidentMessageResultOfClearIdentityCallNotStoredInVariable(
+ methodName: String
+ ): String = "You cleared the original identity with `$methodName` but did not store the " +
+ "result in a variable. You need to store the result in a variable and restore it " +
+ "later."
}
}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/EnforcePermissionDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/EnforcePermissionDetector.kt
index 8011b36c9a8f..9f216189ad62 100644
--- a/tools/lint/checks/src/main/java/com/google/android/lint/EnforcePermissionDetector.kt
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/EnforcePermissionDetector.kt
@@ -16,6 +16,7 @@
package com.google.android.lint
+import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.AnnotationInfo
import com.android.tools.lint.detector.api.AnnotationOrigin
import com.android.tools.lint.detector.api.AnnotationUsageInfo
@@ -32,22 +33,39 @@ import com.android.tools.lint.detector.api.SourceCodeScanner
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UAnnotation
import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UClass
+import org.jetbrains.uast.UMethod
/**
* Lint Detector that ensures that any method overriding a method annotated
* with @EnforcePermission is also annotated with the exact same annotation.
* The intent is to surface the effective permission checks to the service
* implementations.
+ *
+ * This is done with 2 mechanisms:
+ * 1. Visit any annotation usage, to ensure that any derived class will have
+ * the correct annotation on each methods. This is for the top to bottom
+ * propagation.
+ * 2. Visit any annotation, to ensure that if a method is annotated, it has
+ * its ancestor also annotated. This is to avoid having an annotation on a
+ * Java method without the corresponding annotation on the AIDL interface.
*/
class EnforcePermissionDetector : Detector(), SourceCodeScanner {
val ENFORCE_PERMISSION = "android.annotation.EnforcePermission"
+ val BINDER_CLASS = "android.os.Binder"
+ val JAVA_OBJECT = "java.lang.Object"
override fun applicableAnnotations(): List<String> {
return listOf(ENFORCE_PERMISSION)
}
+ override fun getApplicableUastTypes(): List<Class<out UElement>> {
+ return listOf(UAnnotation::class.java)
+ }
+
private fun areAnnotationsEquivalent(
context: JavaContext,
anno1: PsiAnnotation,
@@ -74,6 +92,73 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner {
return true
}
+ private fun compareMethods(
+ context: JavaContext,
+ element: UElement,
+ overridingMethod: PsiMethod,
+ overriddenMethod: PsiMethod,
+ checkEquivalence: Boolean = true
+ ) {
+ val overridingAnnotation = overridingMethod.getAnnotation(ENFORCE_PERMISSION)
+ val overriddenAnnotation = overriddenMethod.getAnnotation(ENFORCE_PERMISSION)
+ val location = context.getLocation(element)
+ val overridingClass = overridingMethod.parent as PsiClass
+ val overriddenClass = overriddenMethod.parent as PsiClass
+ val overridingName = "${overridingClass.name}.${overridingMethod.name}"
+ val overriddenName = "${overriddenClass.name}.${overriddenMethod.name}"
+ if (overridingAnnotation == null) {
+ val msg = "The method $overridingName overrides the method $overriddenName which " +
+ "is annotated with @EnforcePermission. The same annotation must be used " +
+ "on $overridingName"
+ context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
+ } else if (overriddenAnnotation == null) {
+ val msg = "The method $overridingName overrides the method $overriddenName which " +
+ "is not annotated with @EnforcePermission. The same annotation must be " +
+ "used on $overriddenName. Did you forget to annotate the AIDL definition?"
+ context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
+ } else if (checkEquivalence && !areAnnotationsEquivalent(
+ context, overridingAnnotation, overriddenAnnotation)) {
+ val msg = "The method $overridingName is annotated with " +
+ "${overridingAnnotation.text} which differs from the overridden " +
+ "method $overriddenName: ${overriddenAnnotation.text}. The same " +
+ "annotation must be used for both methods."
+ context.report(ISSUE_MISMATCHING_ENFORCE_PERMISSION, element, location, msg)
+ }
+ }
+
+ private fun compareClasses(
+ context: JavaContext,
+ element: UElement,
+ newClass: PsiClass,
+ extendedClass: PsiClass,
+ checkEquivalence: Boolean = true
+ ) {
+ val newAnnotation = newClass.getAnnotation(ENFORCE_PERMISSION)
+ val extendedAnnotation = extendedClass.getAnnotation(ENFORCE_PERMISSION)
+
+ val location = context.getLocation(element)
+ val newClassName = newClass.qualifiedName
+ val extendedClassName = extendedClass.qualifiedName
+ if (newAnnotation == null) {
+ val msg = "The class $newClassName extends the class $extendedClassName which " +
+ "is annotated with @EnforcePermission. The same annotation must be used " +
+ "on $newClassName."
+ context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
+ } else if (extendedAnnotation == null) {
+ val msg = "The class $newClassName extends the class $extendedClassName which " +
+ "is not annotated with @EnforcePermission. The same annotation must be used " +
+ "on $extendedClassName. Did you forget to annotate the AIDL definition?"
+ context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
+ } else if (checkEquivalence && !areAnnotationsEquivalent(
+ context, newAnnotation, extendedAnnotation)) {
+ val msg = "The class $newClassName is annotated with ${newAnnotation.text} " +
+ "which differs from the parent class $extendedClassName: " +
+ "${extendedAnnotation.text}. The same annotation must be used for " +
+ "both classes."
+ context.report(ISSUE_MISMATCHING_ENFORCE_PERMISSION, element, location, msg)
+ }
+ }
+
override fun visitAnnotationUsage(
context: JavaContext,
element: UElement,
@@ -83,48 +168,42 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner {
if (usageInfo.type == AnnotationUsageType.EXTENDS) {
val newClass = element.sourcePsi?.parent?.parent as PsiClass
val extendedClass: PsiClass = usageInfo.referenced as PsiClass
- val newAnnotation = newClass.getAnnotation(ENFORCE_PERMISSION)
- val extendedAnnotation = extendedClass.getAnnotation(ENFORCE_PERMISSION)!!
-
- val location = context.getLocation(element)
- val newClassName = newClass.qualifiedName
- val extendedClassName = extendedClass.qualifiedName
- if (newAnnotation == null) {
- val msg = "The class $newClassName extends the class $extendedClassName which " +
- "is annotated with @EnforcePermission. The same annotation must be used " +
- "on $newClassName."
- context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
- } else if (!areAnnotationsEquivalent(context, newAnnotation, extendedAnnotation)) {
- val msg = "The class $newClassName is annotated with ${newAnnotation.text} " +
- "which differs from the parent class $extendedClassName: " +
- "${extendedAnnotation.text}. The same annotation must be used for " +
- "both classes."
- context.report(ISSUE_MISMATCHING_ENFORCE_PERMISSION, element, location, msg)
- }
+ compareClasses(context, element, newClass, extendedClass)
} else if (usageInfo.type == AnnotationUsageType.METHOD_OVERRIDE &&
annotationInfo.origin == AnnotationOrigin.METHOD) {
val overridingMethod = element.sourcePsi as PsiMethod
val overriddenMethod = usageInfo.referenced as PsiMethod
- val overridingAnnotation = overridingMethod.getAnnotation(ENFORCE_PERMISSION)
- val overriddenAnnotation = overriddenMethod.getAnnotation(ENFORCE_PERMISSION)!!
-
- val location = context.getLocation(element)
- val overridingClass = overridingMethod.parent as PsiClass
- val overriddenClass = overriddenMethod.parent as PsiClass
- val overridingName = "${overridingClass.name}.${overridingMethod.name}"
- val overriddenName = "${overriddenClass.name}.${overriddenMethod.name}"
- if (overridingAnnotation == null) {
- val msg = "The method $overridingName overrides the method $overriddenName which " +
- "is annotated with @EnforcePermission. The same annotation must be used " +
- "on $overridingName"
- context.report(ISSUE_MISSING_ENFORCE_PERMISSION, element, location, msg)
- } else if (!areAnnotationsEquivalent(
- context, overridingAnnotation, overriddenAnnotation)) {
- val msg = "The method $overridingName is annotated with " +
- "${overridingAnnotation.text} which differs from the overridden " +
- "method $overriddenName: ${overriddenAnnotation.text}. The same " +
- "annotation must be used for both methods."
- context.report(ISSUE_MISMATCHING_ENFORCE_PERMISSION, element, location, msg)
+ compareMethods(context, element, overridingMethod, overriddenMethod)
+ }
+ }
+
+ override fun createUastHandler(context: JavaContext): UElementHandler {
+ return object : UElementHandler() {
+ override fun visitAnnotation(node: UAnnotation) {
+ if (node.qualifiedName != ENFORCE_PERMISSION) {
+ return
+ }
+ val method = node.uastParent as? UMethod
+ val klass = node.uastParent as? UClass
+ if (klass != null) {
+ val newClass = klass as PsiClass
+ val extendedClass = newClass.getSuperClass()
+ if (extendedClass != null && extendedClass.qualifiedName != JAVA_OBJECT) {
+ // The equivalence check can be skipped, if both classes are
+ // annotated, it will be verified by visitAnnotationUsage.
+ compareClasses(context, klass, newClass,
+ extendedClass, checkEquivalence = false)
+ }
+ } else if (method != null) {
+ val overridingMethod = method as PsiMethod
+ val parents = overridingMethod.findSuperMethods()
+ for (overriddenMethod in parents) {
+ // The equivalence check can be skipped, if both methods are
+ // annotated, it will be verified by visitAnnotationUsage.
+ compareMethods(context, method, overridingMethod,
+ overriddenMethod, checkEquivalence = false)
+ }
+ }
}
}
}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt
new file mode 100644
index 000000000000..192dba17dd5b
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint
+
+import com.android.tools.lint.client.api.UastParser
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.interprocedural.CallGraph
+import com.android.tools.lint.detector.api.interprocedural.CallGraphResult
+import com.android.tools.lint.detector.api.interprocedural.searchForPaths
+import com.intellij.psi.PsiAnonymousClass
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.UParameter
+import org.jetbrains.uast.USimpleNameReferenceExpression
+import org.jetbrains.uast.visitor.AbstractUastVisitor
+import java.util.LinkedList
+
+/**
+ * A lint checker to detect potential package visibility issues for system's APIs. APIs working
+ * in the system_server and taking the package name as a parameter may have chance to reveal
+ * package existence status on the device, and break the
+ * <a href="https://developer.android.com/about/versions/11/privacy/package-visibility">
+ * Package Visibility</a> that we introduced in Android 11.
+ * <p>
+ * Take an example of the API `boolean setFoo(String packageName)`, a malicious app may have chance
+ * to detect package existence state on the device from the result of the API, if there is no
+ * package visibility filtering rule or uid identify checks applying to the parameter of the
+ * package name.
+ */
+class PackageVisibilityDetector : Detector(), SourceCodeScanner {
+
+ // Enables call graph analysis
+ override fun isCallGraphRequired(): Boolean = true
+
+ override fun analyzeCallGraph(
+ context: Context,
+ callGraph: CallGraphResult
+ ) {
+ val systemServerApiNodes = callGraph.callGraph.nodes.filter(::isSystemServerApi)
+ val sinkMethodNodes = callGraph.callGraph.nodes.filter {
+ // TODO(b/228285232): Remove enforce permission sink methods
+ isNodeInList(it, ENFORCE_PERMISSION_METHODS) || isNodeInList(it, APPOPS_METHODS)
+ }
+ val parser = context.client.getUastParser(context.project)
+ analyzeApisContainPackageNameParameters(
+ context, parser, systemServerApiNodes, sinkMethodNodes)
+ }
+
+ /**
+ * Looking for API contains package name parameters, report the lint issue if the API does not
+ * invoke any sink methods.
+ */
+ private fun analyzeApisContainPackageNameParameters(
+ context: Context,
+ parser: UastParser,
+ systemServerApiNodes: List<CallGraph.Node>,
+ sinkMethodNodes: List<CallGraph.Node>
+ ) {
+ for (apiNode in systemServerApiNodes) {
+ val apiMethod = apiNode.getUMethod() ?: continue
+ val pkgNameParamIndexes = apiMethod.uastParameters.mapIndexedNotNull { index, param ->
+ if (Parameter(param) in PACKAGE_NAME_PATTERNS && apiNode.isArgumentInUse(index)) {
+ index
+ } else {
+ null
+ }
+ }.takeIf(List<Int>::isNotEmpty) ?: continue
+
+ for (pkgNameParamIndex in pkgNameParamIndexes) {
+ // Trace the call path of the method's argument, pass the lint checks if a sink
+ // method is found
+ if (traceArgumentCallPath(
+ apiNode, pkgNameParamIndex, PACKAGE_NAME_SINK_METHOD_LIST)) {
+ continue
+ }
+ // Pass the check if one of the sink methods is invoked
+ if (hasValidPath(
+ searchForPaths(
+ sources = listOf(apiNode),
+ isSink = { it in sinkMethodNodes },
+ getNeighbors = { node -> node.edges.map { it.node!! } }
+ )
+ )
+ ) continue
+
+ // Report issue
+ val reportElement = apiMethod.uastParameters[pkgNameParamIndex] as UElement
+ val location = parser.createLocation(reportElement)
+ context.report(
+ ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
+ location,
+ getMsgPackageNameNoPackageVisibilityFilters(apiMethod, pkgNameParamIndex)
+ )
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the method associated with the given node is a system server's
+ * public API that extends from Stub class.
+ */
+ private fun isSystemServerApi(
+ node: CallGraph.Node
+ ): Boolean {
+ val method = node.getUMethod() ?: return false
+ if (!method.hasModifierProperty("public") ||
+ method.uastBody == null ||
+ method.containingClass is PsiAnonymousClass) {
+ return false
+ }
+ val className = method.containingClass?.qualifiedName ?: return false
+ if (!className.startsWith(SYSTEM_PACKAGE_PREFIX)) {
+ return false
+ }
+ return (method.containingClass ?: return false).supers
+ .filter { it.name == CLASS_STUB }
+ .filter { it.qualifiedName !in BYPASS_STUBS }
+ .any { it.findMethodBySignature(method, /* checkBases */ true) != null }
+ }
+
+ /**
+ * Returns {@code true} if the list contains the node of the call graph.
+ */
+ private fun isNodeInList(
+ node: CallGraph.Node,
+ filters: List<Method>
+ ): Boolean {
+ val method = node.getUMethod() ?: return false
+ return Method(method) in filters
+ }
+
+ /**
+ * Trace the call paths of the argument of the method in the start entry. Return {@code true}
+ * if one of methods in the sink call list is invoked.
+ * Take an example of the call path:
+ * foo(packageName) -> a(packageName) -> b(packageName) -> filterAppAccess()
+ * It returns {@code true} if the filterAppAccess() is in the sink call list.
+ */
+ private fun traceArgumentCallPath(
+ apiNode: CallGraph.Node,
+ pkgNameParamIndex: Int,
+ sinkList: List<Method>
+ ): Boolean {
+ val startEntry = TraceEntry(apiNode, pkgNameParamIndex)
+ val traceQueue = LinkedList<TraceEntry>().apply { add(startEntry) }
+ val allVisits = mutableSetOf<TraceEntry>().apply { add(startEntry) }
+ while (!traceQueue.isEmpty()) {
+ val entry = traceQueue.poll()
+ val entryNode = entry.node
+ val entryMethod = entryNode.getUMethod() ?: continue
+ val entryArgumentName = entryMethod.uastParameters[entry.argumentIndex].name
+ for (outEdge in entryNode.edges) {
+ val outNode = outEdge.node ?: continue
+ val outMethod = outNode.getUMethod() ?: continue
+ val outArgumentIndex =
+ outEdge.call?.findArgumentIndex(
+ entryArgumentName, outMethod.uastParameters.size)
+ val sinkMethod = findInSinkList(outMethod, sinkList)
+ if (sinkMethod == null) {
+ if (outArgumentIndex == null) {
+ // Path is not relevant to the sink method and argument
+ continue
+ }
+ // Path is relevant to the argument, add a new trace entry if never visit before
+ val newEntry = TraceEntry(outNode, outArgumentIndex)
+ if (newEntry !in allVisits) {
+ traceQueue.add(newEntry)
+ allVisits.add(newEntry)
+ }
+ continue
+ }
+ if (sinkMethod.matchArgument && outArgumentIndex == null) {
+ // The sink call is required to match the argument, but not found
+ continue
+ }
+ if (sinkMethod.checkCaller &&
+ entryMethod.isInClearCallingIdentityScope(outEdge.call!!)) {
+ // The sink call is in the scope of Binder.clearCallingIdentify
+ continue
+ }
+ // A sink method is matched
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * Returns the UMethod associated with the given node of call graph.
+ */
+ private fun CallGraph.Node.getUMethod(): UMethod? = this.target.element as? UMethod
+
+ /**
+ * Returns the system module name (e.g. com.android.server.pm) of the method of the
+ * call graph node.
+ */
+ private fun CallGraph.Node.getModuleName(): String? {
+ val method = getUMethod() ?: return null
+ val className = method.containingClass?.qualifiedName ?: return null
+ if (!className.startsWith(SYSTEM_PACKAGE_PREFIX)) {
+ return null
+ }
+ val dotPos = className.indexOf(".", SYSTEM_PACKAGE_PREFIX.length)
+ if (dotPos == -1) {
+ return SYSTEM_PACKAGE_PREFIX
+ }
+ return className.substring(0, dotPos)
+ }
+
+ /**
+ * Return {@code true} if the argument in the method's body is in-use.
+ */
+ private fun CallGraph.Node.isArgumentInUse(argIndex: Int): Boolean {
+ val method = getUMethod() ?: return false
+ val argumentName = method.uastParameters[argIndex].name
+ var foundArg = false
+ val methodVisitor = object : AbstractUastVisitor() {
+ override fun visitSimpleNameReferenceExpression(
+ node: USimpleNameReferenceExpression
+ ): Boolean {
+ if (node.identifier == argumentName) {
+ foundArg = true
+ }
+ return true
+ }
+ }
+ method.uastBody?.accept(methodVisitor)
+ return foundArg
+ }
+
+ /**
+ * Given an argument name, returns the index of argument in the call expression.
+ */
+ private fun UCallExpression.findArgumentIndex(
+ argumentName: String,
+ parameterSize: Int
+ ): Int? {
+ if (valueArgumentCount == 0 || parameterSize == 0) {
+ return null
+ }
+ var match = false
+ val argVisitor = object : AbstractUastVisitor() {
+ override fun visitSimpleNameReferenceExpression(
+ node: USimpleNameReferenceExpression
+ ): Boolean {
+ if (node.identifier == argumentName) {
+ match = true
+ }
+ return true
+ }
+ override fun visitCallExpression(node: UCallExpression): Boolean {
+ return true
+ }
+ }
+ valueArguments.take(parameterSize).forEachIndexed { index, argument ->
+ argument.accept(argVisitor)
+ if (match) {
+ return index
+ }
+ }
+ return null
+ }
+
+ /**
+ * Given a UMethod, returns a method from the sink method list.
+ */
+ private fun findInSinkList(
+ uMethod: UMethod,
+ sinkCallList: List<Method>
+ ): Method? {
+ return sinkCallList.find {
+ it == Method(uMethod) ||
+ it == Method(uMethod.containingClass?.qualifiedName ?: "", "*")
+ }
+ }
+
+ /**
+ * Returns {@code true} if the call expression is in the scope of the
+ * Binder.clearCallingIdentify.
+ */
+ private fun UMethod.isInClearCallingIdentityScope(call: UCallExpression): Boolean {
+ var isInScope = false
+ val methodVisitor = object : AbstractUastVisitor() {
+ private var clearCallingIdentity = 0
+ override fun visitCallExpression(node: UCallExpression): Boolean {
+ if (call == node && clearCallingIdentity != 0) {
+ isInScope = true
+ return true
+ }
+ val visitMethod = Method(node.resolve() ?: return false)
+ if (visitMethod == METHOD_CLEAR_CALLING_IDENTITY) {
+ clearCallingIdentity++
+ } else if (visitMethod == METHOD_RESTORE_CALLING_IDENTITY) {
+ clearCallingIdentity--
+ }
+ return false
+ }
+ }
+ accept(methodVisitor)
+ return isInScope
+ }
+
+ /**
+ * Checks the module name of the start node and the last node that invokes the sink method
+ * (e.g. checkPermission) in a path, returns {@code true} if one of the paths has the same
+ * module name for both nodes.
+ */
+ private fun hasValidPath(paths: Collection<List<CallGraph.Node>>): Boolean {
+ for (pathNodes in paths) {
+ if (pathNodes.size < VALID_CALL_PATH_NODES_SIZE) {
+ continue
+ }
+ val startModule = pathNodes[0].getModuleName() ?: continue
+ val lastCallModule = pathNodes[pathNodes.size - 2].getModuleName() ?: continue
+ if (startModule == lastCallModule) {
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * A data class to represent the method.
+ */
+ private data class Method(
+ val clazz: String,
+ val name: String
+ ) {
+ // Used by traceArgumentCallPath to indicate that the method is required to match the
+ // argument name
+ var matchArgument = true
+
+ // Used by traceArgumentCallPath to indicate that the method is required to check whether
+ // the Binder.clearCallingIdentity is invoked.
+ var checkCaller = false
+
+ constructor(
+ clazz: String,
+ name: String,
+ matchArgument: Boolean = true,
+ checkCaller: Boolean = false
+ ): this(clazz, name) {
+ this.matchArgument = matchArgument
+ this.checkCaller = checkCaller
+ }
+
+ constructor(
+ method: PsiMethod
+ ): this(method.containingClass?.qualifiedName ?: "", method.name)
+ }
+
+ /**
+ * A data class to represent the parameter of the method. The parameter name is converted to
+ * lower case letters for comparison.
+ */
+ private data class Parameter private constructor(
+ val typeName: String,
+ val parameterName: String
+ ) {
+ constructor(uParameter: UParameter): this(
+ uParameter.type.canonicalText,
+ uParameter.name.lowercase()
+ )
+
+ companion object {
+ fun create(typeName: String, parameterName: String) =
+ Parameter(typeName, parameterName.lowercase())
+ }
+ }
+
+ /**
+ * A data class wraps a method node of the call graph and an index that indicates an
+ * argument of the method to record call trace information.
+ */
+ private data class TraceEntry(
+ val node: CallGraph.Node,
+ val argumentIndex: Int
+ )
+
+ companion object {
+ private const val SYSTEM_PACKAGE_PREFIX = "com.android.server."
+ // A valid call path list needs to contain a start node and a sink node
+ private const val VALID_CALL_PATH_NODES_SIZE = 2
+
+ private const val CLASS_STUB = "Stub"
+ private const val CLASS_STRING = "java.lang.String"
+ private const val CLASS_PACKAGE_MANAGER = "android.content.pm.PackageManager"
+ private const val CLASS_IPACKAGE_MANAGER = "android.content.pm.IPackageManager"
+ private const val CLASS_APPOPS_MANAGER = "android.app.AppOpsManager"
+ private const val CLASS_CONTEXT = "android.content.Context"
+ private const val CLASS_BINDER = "android.os.Binder"
+ private const val CLASS_PACKAGE_MANAGER_INTERNAL =
+ "android.content.pm.PackageManagerInternal"
+ private const val CLASS_ACTIVITY_MANAGER_SERVICE =
+ "com.android.server.am.ActivityManagerService"
+ private const val CLASS_ACTIVITY_MANAGER_INTERNAL =
+ "android.app.ActivityManagerInternal"
+
+ // Patterns of package name parameter
+ private val PACKAGE_NAME_PATTERNS = setOf(
+ Parameter.create(CLASS_STRING, "packageName"),
+ Parameter.create(CLASS_STRING, "callingPackage"),
+ Parameter.create(CLASS_STRING, "callingPackageName"),
+ Parameter.create(CLASS_STRING, "pkgName"),
+ Parameter.create(CLASS_STRING, "callingPkg"),
+ Parameter.create(CLASS_STRING, "pkg")
+ )
+
+ // Package manager APIs
+ private val PACKAGE_NAME_SINK_METHOD_LIST = listOf(
+ Method(CLASS_PACKAGE_MANAGER_INTERNAL, "filterAppAccess", matchArgument = false),
+ Method(CLASS_PACKAGE_MANAGER_INTERNAL, "canQueryPackage"),
+ Method(CLASS_PACKAGE_MANAGER_INTERNAL, "isSameApp"),
+ Method(CLASS_PACKAGE_MANAGER, "*", checkCaller = true),
+ Method(CLASS_IPACKAGE_MANAGER, "*", checkCaller = true),
+ Method(CLASS_PACKAGE_MANAGER, "getPackagesForUid", matchArgument = false),
+ Method(CLASS_IPACKAGE_MANAGER, "getPackagesForUid", matchArgument = false)
+ )
+
+ // AppOps APIs which include uid and package visibility filters checks
+ private val APPOPS_METHODS = listOf(
+ Method(CLASS_APPOPS_MANAGER, "noteOp"),
+ Method(CLASS_APPOPS_MANAGER, "noteOpNoThrow"),
+ Method(CLASS_APPOPS_MANAGER, "noteOperation"),
+ Method(CLASS_APPOPS_MANAGER, "noteProxyOp"),
+ Method(CLASS_APPOPS_MANAGER, "noteProxyOpNoThrow"),
+ Method(CLASS_APPOPS_MANAGER, "startOp"),
+ Method(CLASS_APPOPS_MANAGER, "startOpNoThrow"),
+ Method(CLASS_APPOPS_MANAGER, "FinishOp"),
+ Method(CLASS_APPOPS_MANAGER, "finishProxyOp"),
+ Method(CLASS_APPOPS_MANAGER, "checkPackage")
+ )
+
+ // Enforce permission APIs
+ private val ENFORCE_PERMISSION_METHODS = listOf(
+ Method(CLASS_CONTEXT, "checkPermission"),
+ Method(CLASS_CONTEXT, "checkCallingPermission"),
+ Method(CLASS_CONTEXT, "checkCallingOrSelfPermission"),
+ Method(CLASS_CONTEXT, "enforcePermission"),
+ Method(CLASS_CONTEXT, "enforceCallingPermission"),
+ Method(CLASS_CONTEXT, "enforceCallingOrSelfPermission"),
+ Method(CLASS_ACTIVITY_MANAGER_SERVICE, "checkPermission"),
+ Method(CLASS_ACTIVITY_MANAGER_INTERNAL, "enforceCallingPermission")
+ )
+
+ private val BYPASS_STUBS = listOf(
+ "android.content.pm.IPackageDataObserver.Stub",
+ "android.content.pm.IPackageDeleteObserver.Stub",
+ "android.content.pm.IPackageDeleteObserver2.Stub",
+ "android.content.pm.IPackageInstallObserver2.Stub",
+ "com.android.internal.app.IAppOpsCallback.Stub",
+
+ // TODO(b/228285637): Do not bypass PackageManagerService API
+ "android.content.pm.IPackageManager.Stub",
+ "android.content.pm.IPackageManagerNative.Stub"
+ )
+
+ private val METHOD_CLEAR_CALLING_IDENTITY =
+ Method(CLASS_BINDER, "clearCallingIdentity")
+ private val METHOD_RESTORE_CALLING_IDENTITY =
+ Method(CLASS_BINDER, "restoreCallingIdentity")
+
+ private fun getMsgPackageNameNoPackageVisibilityFilters(
+ method: UMethod,
+ argumentIndex: Int
+ ): String = "Api: ${method.name} contains a package name parameter: " +
+ "${method.uastParameters[argumentIndex].name} does not apply " +
+ "package visibility filtering rules."
+
+ private val EXPLANATION = """
+ APIs working in the system_server and taking the package name as a parameter may have
+ chance to reveal package existence status on the device, and break the package
+ visibility that we introduced in Android 11.
+ (https://developer.android.com/about/versions/11/privacy/package-visibility)
+
+ Take an example of the API `boolean setFoo(String packageName)`, a malicious app may
+ have chance to get package existence state on the device from the result of the API,
+ if there is no package visibility filtering rule or uid identify checks applying to
+ the parameter of the package name.
+
+ To resolve it, you could apply package visibility filtering rules to the package name
+ via PackageManagerInternal.filterAppAccess API, before starting to use the package name.
+ If the parameter is a calling package name, use the PackageManager API such as
+ PackageManager.getPackagesForUid to verify the calling identify.
+ """
+
+ val ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS = Issue.create(
+ id = "ApiMightLeakAppVisibility",
+ briefDescription = "Api takes package name parameter doesn't apply " +
+ "package visibility filters",
+ explanation = EXPLANATION,
+ category = Category.SECURITY,
+ priority = 1,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ PackageVisibilityDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+ }
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt
new file mode 100644
index 000000000000..cc2ab19c97f1
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint.parcel
+
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.LintFix
+import com.android.tools.lint.detector.api.Location
+import com.intellij.psi.PsiCallExpression
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiIntersectionType
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiTypeParameter
+import com.intellij.psi.PsiWildcardType
+import org.jetbrains.kotlin.utils.addToStdlib.cast
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UVariable
+
+/**
+ * Subclass this class and override {@link #getBoundingClass} to report an unsafe Parcel API issue
+ * with a fix that migrates towards the new safer API by appending an argument in the form of
+ * {@code com.package.ItemType.class} coming from the result of the overridden method.
+ */
+abstract class CallMigrator(
+ val method: Method,
+ private val rejects: Set<String> = emptySet(),
+) {
+ open fun report(context: JavaContext, call: UCallExpression, method: PsiMethod) {
+ val location = context.getLocation(call)
+ val itemType = getBoundingClass(context, call, method)
+ val fix = (itemType as? PsiClassType)?.let { type ->
+ getParcelFix(location, this.method.name, getArgumentSuffix(type))
+ }
+ val message = "Unsafe `Parcel.${this.method.name}()` API usage"
+ context.report(SaferParcelChecker.ISSUE_UNSAFE_API_USAGE, call, location, message, fix)
+ }
+
+ protected open fun getArgumentSuffix(type: PsiClassType) =
+ ", ${type.rawType().canonicalText}.class"
+
+ protected open fun getBoundingClass(
+ context: JavaContext,
+ call: UCallExpression,
+ method: PsiMethod,
+ ): PsiType? = null
+
+ protected fun getItemType(type: PsiType, container: String): PsiClassType? {
+ val supers = getParentTypes(type).mapNotNull { it as? PsiClassType }
+ val containerType = supers.firstOrNull { it.rawType().canonicalText == container }
+ ?: return null
+ val itemType = containerType.parameters.getOrNull(0) ?: return null
+ // TODO: Expand to other types, see PsiTypeVisitor
+ return when (itemType) {
+ is PsiClassType -> itemType
+ is PsiWildcardType -> itemType.bound as PsiClassType
+ else -> null
+ }
+ }
+
+ /**
+ * Tries to obtain the type expected by the "receiving" end given a certain {@link UExpression}.
+ *
+ * This could be an assignment, an argument passed to a method call, to a constructor call, a
+ * type cast, etc. If no receiving end is found, the type of the UExpression itself is returned.
+ */
+ protected fun getReceivingType(expression: UExpression): PsiType? {
+ val parent = expression.uastParent
+ val type = when (parent) {
+ is UCallExpression -> {
+ val i = parent.valueArguments.indexOf(expression)
+ val psiCall = parent.sourcePsi as? PsiCallExpression ?: return null
+ val typeSubstitutor = psiCall.resolveMethodGenerics().substitutor
+ val method = psiCall.resolveMethod()!!
+ method.getSignature(typeSubstitutor).parameterTypes[i]
+ }
+ is UVariable -> parent.type
+ is UExpression -> parent.getExpressionType()
+ else -> null
+ }
+ return filter(type ?: expression.getExpressionType())
+ }
+
+ private fun filter(type: PsiType?): PsiType? {
+ // It's important that PsiIntersectionType case is above the one that check the type in
+ // rejects, because for intersect types, the canonicalText is one of the terms.
+ if (type is PsiIntersectionType) {
+ return type.conjuncts.mapNotNull(this::filter).firstOrNull()
+ }
+ if (type == null || type.canonicalText in rejects) {
+ return null
+ }
+ if (type is PsiClassType && type.resolve() is PsiTypeParameter) {
+ return null
+ }
+ return type
+ }
+
+ private fun getParentTypes(type: PsiType): Set<PsiType> =
+ type.superTypes.flatMap(::getParentTypes).toSet() + type
+
+ protected fun getParcelFix(location: Location, method: String, arguments: String) =
+ LintFix
+ .create()
+ .name("Migrate to safer Parcel.$method() API")
+ .replace()
+ .range(location)
+ .pattern("$method\\s*\\(((?:.|\\n)*)\\)")
+ .with("\\k<1>$arguments")
+ .autoFix()
+ .build()
+}
+
+/**
+ * This class derives the type to be appended by inferring the generic type of the {@code container}
+ * type (eg. "java.util.List") of the {@code argument}-th argument.
+ */
+class ContainerArgumentMigrator(
+ method: Method,
+ private val argument: Int,
+ private val container: String,
+ rejects: Set<String> = emptySet(),
+) : CallMigrator(method, rejects) {
+ override fun getBoundingClass(
+ context: JavaContext, call: UCallExpression, method: PsiMethod
+ ): PsiType? {
+ val firstParamType = call.valueArguments[argument].getExpressionType() ?: return null
+ return getItemType(firstParamType, container)!!
+ }
+
+ /**
+ * We need to insert a casting construct in the class parameter. For example:
+ * (Class<Foo<Bar>>) (Class<?>) Foo.class.
+ * This is needed for when the arguments of the conflict (eg. when there is List<Foo<Bar>> and
+ * class type is Class<Foo?).
+ */
+ override fun getArgumentSuffix(type: PsiClassType): String {
+ if (type.parameters.isNotEmpty()) {
+ val rawType = type.rawType()
+ return ", (Class<${type.canonicalText}>) (Class<?>) ${rawType.canonicalText}.class"
+ }
+ return super.getArgumentSuffix(type)
+ }
+}
+
+/**
+ * This class derives the type to be appended by inferring the generic type of the {@code container}
+ * type (eg. "java.util.List") of the return type of the method.
+ */
+class ContainerReturnMigrator(
+ method: Method,
+ private val container: String,
+ rejects: Set<String> = emptySet(),
+) : CallMigrator(method, rejects) {
+ override fun getBoundingClass(
+ context: JavaContext, call: UCallExpression, method: PsiMethod
+ ): PsiType? {
+ val type = getReceivingType(call.uastParent as UExpression) ?: return null
+ return getItemType(type, container)
+ }
+}
+
+/**
+ * This class derives the type to be appended by inferring the expected type for the method result.
+ */
+class ReturnMigrator(
+ method: Method,
+ rejects: Set<String> = emptySet(),
+) : CallMigrator(method, rejects) {
+ override fun getBoundingClass(
+ context: JavaContext, call: UCallExpression, method: PsiMethod
+ ): PsiType? {
+ return getReceivingType(call.uastParent as UExpression)
+ }
+}
+
+/**
+ * This class appends the class loader and the class object by deriving the type from the method
+ * result.
+ */
+class ReturnMigratorWithClassLoader(
+ method: Method,
+ rejects: Set<String> = emptySet(),
+) : CallMigrator(method, rejects) {
+ override fun getBoundingClass(
+ context: JavaContext, call: UCallExpression, method: PsiMethod
+ ): PsiType? {
+ return getReceivingType(call.uastParent as UExpression)
+ }
+
+ override fun getArgumentSuffix(type: PsiClassType): String =
+ "${type.rawType().canonicalText}.class.getClassLoader(), " +
+ "${type.rawType().canonicalText}.class"
+
+} \ No newline at end of file
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt
new file mode 100644
index 000000000000..c032fa29f254
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint.parcel
+
+data class Method(
+ val params: List<String>,
+ val clazz: String,
+ val name: String,
+ val parameters: List<String>
+) {
+ constructor(
+ clazz: String,
+ name: String,
+ parameters: List<String>
+ ) : this(
+ listOf(), clazz, name, parameters
+ )
+
+ val signature: String
+ get() {
+ val prefix = if (params.isEmpty()) "" else "${params.joinToString(", ", "<", ">")} "
+ return "$prefix$clazz.$name(${parameters.joinToString()})"
+ }
+} \ No newline at end of file
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt
new file mode 100644
index 000000000000..89dbcaeac3a7
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint.parcel
+
+import com.android.tools.lint.detector.api.*
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiSubstitutor
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiTypeParameter
+import org.jetbrains.uast.UCallExpression
+import java.util.*
+
+class SaferParcelChecker : Detector(), SourceCodeScanner {
+ override fun getApplicableMethodNames(): List<String> =
+ MIGRATORS
+ .map(CallMigrator::method)
+ .map(Method::name)
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ if (!isAtLeastT(context)) return
+ val signature = getSignature(method)
+ val migrator = MIGRATORS.firstOrNull { it.method.signature == signature } ?: return
+ migrator.report(context, node, method)
+ }
+
+ private fun getSignature(method: PsiMethod): String {
+ val name = UastLintUtils.getQualifiedName(method)
+ val signature = method.getSignature(PsiSubstitutor.EMPTY)
+ val parameters =
+ signature.parameterTypes.joinToString(transform = PsiType::getCanonicalText)
+ val types = signature.typeParameters.map(PsiTypeParameter::getName)
+ val prefix = if (types.isEmpty()) "" else types.joinToString(", ", "<", ">") + " "
+ return "$prefix$name($parameters)"
+ }
+
+ /** Taken from androidx-main:core/core/src/main/java/androidx/core/os/BuildCompat.java */
+ private fun isAtLeastT(context: Context): Boolean {
+ val project = if (context.isGlobalAnalysis()) context.mainProject else context.project
+ return project.isAndroidProject
+ && project.minSdkVersion.featureLevel >= 32
+ && isAtLeastPreReleaseCodename("Tiramisu", project.minSdkVersion.codename)
+ }
+
+ /** Taken from androidx-main:core/core/src/main/java/androidx/core/os/BuildCompat.java */
+ private fun isAtLeastPreReleaseCodename(min: String, actual: String): Boolean {
+ if (actual == "REL") return false
+ return actual.uppercase(Locale.ROOT) >= min.uppercase(Locale.ROOT)
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE_UNSAFE_API_USAGE: Issue = Issue.create(
+ id = "UnsafeParcelApi",
+ briefDescription = "Use of unsafe Parcel API",
+ explanation = """
+ You are using a deprecated Parcel API that doesn't accept the expected class as\
+ a parameter. This means that unexpected classes could be instantiated and\
+ unexpected code executed.
+
+ Please migrate to the safer alternative that takes an extra Class<T> parameter.
+ """,
+ category = Category.SECURITY,
+ priority = 8,
+ severity = Severity.WARNING,
+
+ implementation = Implementation(
+ SaferParcelChecker::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private val METHOD_READ_SERIALIZABLE = Method("android.os.Parcel", "readSerializable", listOf())
+ private val METHOD_READ_ARRAY_LIST = Method("android.os.Parcel", "readArrayList", listOf("java.lang.ClassLoader"))
+ private val METHOD_READ_LIST = Method("android.os.Parcel", "readList", listOf("java.util.List", "java.lang.ClassLoader"))
+ private val METHOD_READ_PARCELABLE = Method(listOf("T"), "android.os.Parcel", "readParcelable", listOf("java.lang.ClassLoader"))
+ private val METHOD_READ_PARCELABLE_LIST = Method(listOf("T"), "android.os.Parcel", "readParcelableList", listOf("java.util.List<T>", "java.lang.ClassLoader"))
+ private val METHOD_READ_SPARSE_ARRAY = Method(listOf("T"), "android.os.Parcel", "readSparseArray", listOf("java.lang.ClassLoader"))
+
+ // TODO: Write migrators for methods below
+ private val METHOD_READ_ARRAY = Method("android.os.Parcel", "readArray", listOf("java.lang.ClassLoader"))
+ private val METHOD_READ_PARCELABLE_ARRAY = Method("android.os.Parcel", "readParcelableArray", listOf("java.lang.ClassLoader"))
+ private val METHOD_READ_PARCELABLE_CREATOR = Method("android.os.Parcel", "readParcelableCreator", listOf("java.lang.ClassLoader"))
+
+ private val MIGRATORS = listOf(
+ ReturnMigrator(METHOD_READ_PARCELABLE, setOf("android.os.Parcelable")),
+ ContainerArgumentMigrator(METHOD_READ_LIST, 0, "java.util.List"),
+ ContainerReturnMigrator(METHOD_READ_ARRAY_LIST, "java.util.Collection"),
+ ContainerReturnMigrator(METHOD_READ_SPARSE_ARRAY, "android.util.SparseArray"),
+ ContainerArgumentMigrator(METHOD_READ_PARCELABLE_LIST, 0, "java.util.List"),
+ ReturnMigratorWithClassLoader(METHOD_READ_SERIALIZABLE),
+ )
+ }
+} \ No newline at end of file
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
index e1a5c613dee1..d90f3e31baf9 100644
--- a/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
@@ -27,12 +27,13 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
override fun getDetector(): Detector = CallingIdentityTokenDetector()
override fun getIssues(): List<Issue> = listOf(
- CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
- CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
- CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
- CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
- CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
- CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY
+ CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
+ CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
+ CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+ CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+ CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+ CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+ CallingIdentityTokenDetector.ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE
)
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
@@ -41,8 +42,8 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
fun testDoesNotDetectIssuesInCorrectScenario() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -62,22 +63,29 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
} finally {
restoreCallingIdentity(token3);
}
+ final Long token4 = true ? Binder.clearCallingIdentity() : null;
+ try {
+ } finally {
+ if (token4 != null) {
+ restoreCallingIdentity(token4);
+ }
+ }
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expectClean()
+ .run()
+ .expectClean()
}
/** Unused token issue tests */
fun testDetectsUnusedTokens() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -101,12 +109,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:5: Warning: token1 has not been used to \
restore the calling identity. Introduce a try-finally after the \
declaration and call Binder.restoreCallingIdentity(token1) in finally or \
@@ -127,13 +135,13 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 3 warnings
""".addLineContinuation()
- )
+ )
}
fun testDetectsUnusedTokensInScopes() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 {
@@ -152,12 +160,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:5: Warning: token has not been used to \
restore the calling identity. Introduce a try-finally after the \
declaration and call Binder.restoreCallingIdentity(token) in finally or \
@@ -166,13 +174,13 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 1 warnings
""".addLineContinuation()
- )
+ )
}
fun testDoesNotDetectUsedTokensInScopes() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 {
@@ -192,17 +200,17 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expectClean()
+ .run()
+ .expectClean()
}
fun testDetectsUnusedTokensWithSimilarNamesInScopes() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 {
@@ -220,12 +228,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:5: Warning: token has not been used to \
restore the calling identity. Introduce a try-finally after the \
declaration and call Binder.restoreCallingIdentity(token) in finally or \
@@ -240,15 +248,15 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 2 warnings
""".addLineContinuation()
- )
+ )
}
/** Non-final token issue tests */
fun testDetectsNonFinalTokens() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -271,12 +279,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:5: Warning: token1 is a non-final token from \
Binder.clearCallingIdentity(). Add final keyword to token1. \
[NonFinalTokenOfOriginalCallingIdentity]
@@ -294,7 +302,7 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 3 warnings
""".addLineContinuation()
- )
+ )
}
/** Nested clearCallingIdentity() calls issue tests */
@@ -302,8 +310,8 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
fun testDetectsNestedClearCallingIdentityCalls() {
// Pattern: clear - clear - clear - restore - restore - restore
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -326,12 +334,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:7: Warning: The calling identity has already \
been cleared and returned into token1. Move token2 declaration after \
restoring the calling identity with Binder.restoreCallingIdentity(token1). \
@@ -348,15 +356,15 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
0 errors, 2 warnings
""".addLineContinuation()
- )
+ )
}
/** clearCallingIdentity() not followed by try-finally issue tests */
fun testDetectsClearIdentityCallNotFollowedByTryFinally() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder{
@@ -397,12 +405,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:5: Warning: You cleared the calling identity \
and returned the result into token, but the next statement is not a \
try-finally statement. Define a try-finally block after token declaration \
@@ -445,15 +453,15 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 5 warnings
""".addLineContinuation()
- )
+ )
}
/** restoreCallingIdentity() call not in finally block issue tests */
fun testDetectsRestoreCallingIdentityCallNotInFinally() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -482,12 +490,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:10: Warning: \
Binder.restoreCallingIdentity(token) is not an immediate child of the \
finally block of the try statement after token declaration. Surround the c\
@@ -511,13 +519,13 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 3 warnings
""".addLineContinuation()
- )
+ )
}
fun testDetectsRestoreCallingIdentityCallNotInFinallyInScopes() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
public class TestClass1 extends Binder {
@@ -560,12 +568,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:11: Warning: \
Binder.restoreCallingIdentity(token1) is not an immediate child of the \
finally block of the try statement after token1 declaration. Surround the \
@@ -596,15 +604,15 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 4 warnings
""".addLineContinuation()
- )
+ )
}
/** Use of caller-aware methods after clearCallingIdentity() issue tests */
fun testDetectsUseOfCallerAwareMethodsWithClearedIdentityIssuesInScopes() {
lint().files(
- java(
- """
+ java(
+ """
package test.pkg;
import android.os.Binder;
import android.os.UserHandle;
@@ -632,12 +640,12 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
}
}
"""
- ).indented(),
- *stubs
+ ).indented(),
+ *stubs
)
- .run()
- .expect(
- """
+ .run()
+ .expect(
+ """
src/test/pkg/TestClass1.java:8: Warning: You cleared the original identity \
with Binder.clearCallingIdentity() and returned into token, so \
getCallingPid() will be using your own identity instead of the \
@@ -736,13 +744,58 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 errors, 12 warnings
""".addLineContinuation()
- )
+ )
+ }
+
+ /** Result of Binder.clearCallingIdentity() is not stored in a variable issue tests */
+
+ fun testDetectsResultOfClearIdentityCallNotStoredInVariable() {
+ lint().files(
+ java(
+ """
+ package test.pkg;
+ import android.os.Binder;
+ public class TestClass1 extends Binder {
+ private void testMethod() {
+ Binder.clearCallingIdentity();
+ android.os.Binder.clearCallingIdentity();
+ clearCallingIdentity();
+ }
+ }
+ """
+ ).indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass1.java:5: Warning: You cleared the original identity \
+ with Binder.clearCallingIdentity() but did not store the result in a \
+ variable. You need to store the result in a variable and restore it later. \
+ [ResultOfClearIdentityCallNotStoredInVariable]
+ Binder.clearCallingIdentity();
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/test/pkg/TestClass1.java:6: Warning: You cleared the original identity \
+ with android.os.Binder.clearCallingIdentity() but did not store the result \
+ in a variable. You need to store the result in a variable and restore it \
+ later. [ResultOfClearIdentityCallNotStoredInVariable]
+ android.os.Binder.clearCallingIdentity();
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/test/pkg/TestClass1.java:7: Warning: You cleared the original identity \
+ with clearCallingIdentity() but did not store the result in a variable. \
+ You need to store the result in a variable and restore it later. \
+ [ResultOfClearIdentityCallNotStoredInVariable]
+ clearCallingIdentity();
+ ~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 3 warnings
+ """.addLineContinuation()
+ )
}
/** Stubs for classes used for testing */
private val binderStub: TestFile = java(
- """
+ """
package android.os;
public class Binder {
public static final native long clearCallingIdentity() {
@@ -767,7 +820,7 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
).indented()
private val userHandleStub: TestFile = java(
- """
+ """
package android.os;
import android.annotation.AppIdInt;
import android.annotation.UserIdInt;
@@ -792,7 +845,7 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
).indented()
private val userIdIntStub: TestFile = java(
- """
+ """
package android.annotation;
public @interface UserIdInt {
}
@@ -800,7 +853,7 @@ class CallingIdentityTokenDetectorTest : LintDetectorTest() {
).indented()
private val appIdIntStub: TestFile = java(
- """
+ """
package android.annotation;
public @interface AppIdInt {
}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/EnforcePermissionDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/EnforcePermissionDetectorTest.kt
index f5f4ebee24e0..2cfc3fbcefcb 100644
--- a/tools/lint/checks/src/test/java/com/google/android/lint/EnforcePermissionDetectorTest.kt
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/EnforcePermissionDetectorTest.kt
@@ -147,14 +147,57 @@ annotation must be used on TestClass6.testMethod [MissingEnforcePermissionAnnota
1 errors, 0 warnings""".addLineContinuation())
}
+ fun testDetectIssuesExtraAnnotationMethod() {
+ lint().files(java(
+ """
+ package test.pkg;
+ public class TestClass7 extends IBar.Stub {
+ @android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
+ public void testMethod() {}
+ }
+ """).indented(),
+ *stubs
+ )
+ .run()
+ .expect("""src/test/pkg/TestClass7.java:4: Error: The method TestClass7.testMethod \
+overrides the method Stub.testMethod which is not annotated with @EnforcePermission. The same \
+annotation must be used on Stub.testMethod. Did you forget to annotate the AIDL definition? \
+[MissingEnforcePermissionAnnotation]
+ public void testMethod() {}
+ ~~~~~~~~~~
+1 errors, 0 warnings""".addLineContinuation())
+ }
+
+ fun testDetectIssuesExtraAnnotationInterface() {
+ lint().files(java(
+ """
+ package test.pkg;
+ @android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
+ public class TestClass8 extends IBar.Stub {
+ public void testMethod() {}
+ }
+ """).indented(),
+ *stubs
+ )
+ .run()
+ .expect("""src/test/pkg/TestClass8.java:2: Error: The class test.pkg.TestClass8 \
+extends the class IBar.Stub which is not annotated with @EnforcePermission. The same annotation \
+must be used on IBar.Stub. Did you forget to annotate the AIDL definition? \
+[MissingEnforcePermissionAnnotation]
+@android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
+^
+1 errors, 0 warnings""".addLineContinuation())
+ }
+
/* Stubs */
+ // A service with permission annotation on the class.
private val interfaceIFooStub: TestFile = java(
"""
@android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
public interface IFoo {
@android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public static abstract class Stub implements IFoo {
+ public static abstract class Stub extends android.os.Binder implements IFoo {
@Override
public void testMethod() {}
}
@@ -163,10 +206,11 @@ annotation must be used on TestClass6.testMethod [MissingEnforcePermissionAnnota
"""
).indented()
+ // A service with permission annotation on the method.
private val interfaceIFooMethodStub: TestFile = java(
"""
public interface IFooMethod {
- public static abstract class Stub implements IFooMethod {
+ public static abstract class Stub extends android.os.Binder implements IFooMethod {
@Override
@android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
public void testMethod() {}
@@ -177,6 +221,19 @@ annotation must be used on TestClass6.testMethod [MissingEnforcePermissionAnnota
"""
).indented()
+ // A service without any permission annotation.
+ private val interfaceIBarStub: TestFile = java(
+ """
+ public interface IBar {
+ public static abstract class Stub extends android.os.Binder implements IBar {
+ @Override
+ public void testMethod() {}
+ }
+ public void testMethod();
+ }
+ """
+ ).indented()
+
private val manifestPermissionStub: TestFile = java(
"""
package android.Manifest;
@@ -194,7 +251,7 @@ annotation must be used on TestClass6.testMethod [MissingEnforcePermissionAnnota
"""
).indented()
- private val stubs = arrayOf(interfaceIFooStub, interfaceIFooMethodStub,
+ private val stubs = arrayOf(interfaceIFooStub, interfaceIFooMethodStub, interfaceIBarStub,
manifestPermissionStub, enforcePermissionAnnotationStub)
// Substitutes "backslash + new line" with an empty string to imitate line continuation
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt
new file mode 100644
index 000000000000..a70644ab8532
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class PackageVisibilityDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = PackageVisibilityDetector()
+
+ override fun getIssues(): MutableList<Issue> = mutableListOf(
+ PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS
+ )
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ fun testDetectIssuesParameterDoesNotApplyPackageVisibilityFilters() {
+ lint().files(java(
+ """
+ package com.android.server.lint.test;
+ import android.internal.test.IFoo;
+
+ public class TestClass extends IFoo.Stub {
+ @Override
+ public boolean hasPackage(String packageName) {
+ return packageName != null;
+ }
+ }
+ """).indented(), *stubs
+ ).run().expect(
+ """
+ src/com/android/server/lint/test/TestClass.java:6: Warning: \
+ Api: hasPackage contains a package name parameter: packageName does not apply \
+ package visibility filtering rules. \
+ [ApiMightLeakAppVisibility]
+ public boolean hasPackage(String packageName) {
+ ~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectIssuesApiInvokesAppOps() {
+ lint().files(java(
+ """
+ package com.android.server.lint.test;
+ import android.app.AppOpsManager;
+ import android.os.Binder;
+ import android.internal.test.IFoo;
+
+ public class TestClass extends IFoo.Stub {
+ private AppOpsManager mAppOpsManager;
+
+ @Override
+ public boolean hasPackage(String packageName) {
+ checkPackage(packageName);
+ return packageName != null;
+ }
+
+ private void checkPackage(String packageName) {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+ }
+ }
+ """
+ ).indented(), *stubs).run().expectClean()
+ }
+
+ fun testDoesNotDetectIssuesApiInvokesEnforcePermission() {
+ lint().files(java(
+ """
+ package com.android.server.lint.test;
+ import android.content.Context;
+ import android.internal.test.IFoo;
+
+ public class TestClass extends IFoo.Stub {
+ private Context mContext;
+
+ @Override
+ public boolean hasPackage(String packageName) {
+ enforcePermission();
+ return packageName != null;
+ }
+
+ private void enforcePermission() {
+ mContext.checkCallingPermission(
+ android.Manifest.permission.ACCESS_INPUT_FLINGER);
+ }
+ }
+ """
+ ).indented(), *stubs).run().expectClean()
+ }
+
+ fun testDoesNotDetectIssuesApiInvokesPackageManager() {
+ lint().files(java(
+ """
+ package com.android.server.lint.test;
+ import android.content.pm.PackageInfo;
+ import android.content.pm.PackageManager;
+ import android.internal.test.IFoo;
+
+ public class TestClass extends IFoo.Stub {
+ private PackageManager mPackageManager;
+
+ @Override
+ public boolean hasPackage(String packageName) {
+ return getPackageInfo(packageName) != null;
+ }
+
+ private PackageInfo getPackageInfo(String packageName) {
+ try {
+ return mPackageManager.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+ }
+ """
+ ).indented(), *stubs).run().expectClean()
+ }
+
+ fun testDetectIssuesApiInvokesPackageManagerAndClearCallingIdentify() {
+ lint().files(java(
+ """
+ package com.android.server.lint.test;
+ import android.content.pm.PackageInfo;
+ import android.content.pm.PackageManager;
+ import android.internal.test.IFoo;import android.os.Binder;
+
+ public class TestClass extends IFoo.Stub {
+ private PackageManager mPackageManager;
+
+ @Override
+ public boolean hasPackage(String packageName) {
+ return getPackageInfo(packageName) != null;
+ }
+
+ private PackageInfo getPackageInfo(String packageName) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ try {
+ return mPackageManager.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ } finally{
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ """).indented(), *stubs
+ ).run().expect(
+ """
+ src/com/android/server/lint/test/TestClass.java:10: Warning: \
+ Api: hasPackage contains a package name parameter: packageName does not apply \
+ package visibility filtering rules. \
+ [ApiMightLeakAppVisibility]
+ public boolean hasPackage(String packageName) {
+ ~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectIssuesApiNotSystemPackagePrefix() {
+ lint().files(java(
+ """
+ package com.test.not.system.prefix;
+ import android.internal.test.IFoo;
+
+ public class TestClass extends IFoo.Stub {
+ @Override
+ public boolean hasPackage(String packageName) {
+ return packageName != null;
+ }
+ }
+ """
+ ).indented(), *stubs).run().expectClean()
+ }
+
+ private val contextStub: TestFile = java(
+ """
+ package android.content;
+
+ public abstract class Context {
+ public abstract int checkCallingPermission(String permission);
+ }
+ """
+ ).indented()
+
+ private val appOpsManagerStub: TestFile = java(
+ """
+ package android.app;
+
+ public class AppOpsManager {
+ public void checkPackage(int uid, String packageName) {
+ }
+ }
+ """
+ ).indented()
+
+ private val packageManagerStub: TestFile = java(
+ """
+ package android.content.pm;
+ import android.content.pm.PackageInfo;
+
+ public abstract class PackageManager {
+ public static class NameNotFoundException extends AndroidException {
+ }
+
+ public abstract PackageInfo getPackageInfo(String packageName, int flags)
+ throws NameNotFoundException;
+ }
+ """
+ ).indented()
+
+ private val packageInfoStub: TestFile = java(
+ """
+ package android.content.pm;
+ public class PackageInfo {}
+ """
+ ).indented()
+
+ private val binderStub: TestFile = java(
+ """
+ package android.os;
+
+ public class Binder {
+ public static final native long clearCallingIdentity();
+ public static final native void restoreCallingIdentity(long token);
+ public static final native int getCallingUid();
+ }
+ """
+ ).indented()
+
+ private val interfaceIFooStub: TestFile = java(
+ """
+ package android.internal.test;
+ import android.os.Binder;
+
+ public interface IFoo {
+ boolean hasPackage(String packageName);
+ public abstract static class Stub extends Binder implements IFoo {
+ }
+ }
+ """
+ ).indented()
+
+ private val stubs = arrayOf(contextStub, appOpsManagerStub, packageManagerStub,
+ packageInfoStub, binderStub, interfaceIFooStub)
+
+ // Substitutes "backslash + new line" with an empty string to imitate line continuation
+ private fun String.addLineContinuation(): String = this.trimIndent().replace("\\\n", "")
+}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt
new file mode 100644
index 000000000000..05c7850c44c2
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2022 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.google.android.lint.parcel
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.checks.infrastructure.TestMode
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class SaferParcelCheckerTest : LintDetectorTest() {
+ override fun getDetector(): Detector = SaferParcelChecker()
+
+ override fun getIssues(): List<Issue> = listOf(
+ SaferParcelChecker.ISSUE_UNSAFE_API_USAGE
+ )
+
+ override fun lint(): TestLintTask =
+ super.lint()
+ .allowMissingSdk(true)
+ // We don't do partial analysis in the platform
+ .skipTestModes(TestMode.PARTIAL)
+
+ fun testDetectUnsafeReadSerializable() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.os.Parcel;
+ import java.io.Serializable;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ Serializable ans = p.readSerializable();
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .expectIdenticalTestModeOutput(false)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:7: Warning: Unsafe Parcel.readSerializable() \
+ API usage [UnsafeParcelApi]
+ Serializable ans = p.readSerializable();
+ ~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadSerializable() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.os.Parcel;
+ import java.io.Serializable;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ String ans = p.readSerializable(null, String.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ fun testDetectUnsafeReadArrayList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.os.Parcel;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ ArrayList ans = p.readArrayList(null);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:6: Warning: Unsafe Parcel.readArrayList() API \
+ usage [UnsafeParcelApi]
+ ArrayList ans = p.readArrayList(null);
+ ~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadArrayList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ ArrayList<Intent> ans = p.readArrayList(null, Intent.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ fun testDetectUnsafeReadList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import java.util.List;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ List<Intent> list = new ArrayList<Intent>();
+ p.readList(list, null);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:9: Warning: Unsafe Parcel.readList() API usage \
+ [UnsafeParcelApi]
+ p.readList(list, null);
+ ~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import java.util.List;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ List<Intent> list = new ArrayList<Intent>();
+ p.readList(list, null, Intent.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ fun testDetectUnsafeReadParcelable() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ Intent ans = p.readParcelable(null);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:7: Warning: Unsafe Parcel.readParcelable() API \
+ usage [UnsafeParcelApi]
+ Intent ans = p.readParcelable(null);
+ ~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadParcelable() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ Intent ans = p.readParcelable(null, Intent.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ fun testDetectUnsafeReadParcelableList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import java.util.List;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ List<Intent> list = new ArrayList<Intent>();
+ List<Intent> ans = p.readParcelableList(list, null);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:9: Warning: Unsafe Parcel.readParcelableList() \
+ API usage [UnsafeParcelApi]
+ List<Intent> ans = p.readParcelableList(list, null);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadParcelableList() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import java.util.List;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ List<Intent> list = new ArrayList<Intent>();
+ List<Intent> ans =
+ p.readParcelableList(list, null, Intent.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ fun testDetectUnsafeReadSparseArray() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import android.util.SparseArray;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ SparseArray<Intent> ans = p.readSparseArray(null);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:8: Warning: Unsafe Parcel.readSparseArray() API\
+ usage [UnsafeParcelApi]
+ SparseArray<Intent> ans = p.readSparseArray(null);
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """.addLineContinuation()
+ )
+ }
+
+ fun testDoesNotDetectSafeReadSparseArray() {
+ lint()
+ .files(
+ java(
+ """
+ package test.pkg;
+ import android.content.Intent;
+ import android.os.Parcel;
+ import android.util.SparseArray;
+
+ public class TestClass {
+ private TestClass(Parcel p) {
+ SparseArray<Intent> ans =
+ p.readSparseArray(null, Intent.class);
+ }
+ }
+ """
+ ).indented(),
+ *includes
+ )
+ .run()
+ .expect("No warnings.")
+ }
+
+ /** Stubs for classes used for testing */
+
+
+ private val includes =
+ arrayOf(
+ manifest().minSdk("Tiramisu"),
+ java(
+ """
+ package android.os;
+ import java.util.ArrayList;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.HashMap;
+
+ public final class Parcel {
+ // Deprecateds
+ public Object[] readArray(ClassLoader loader) { return null; }
+ public ArrayList readArrayList(ClassLoader loader) { return null; }
+ public HashMap readHashMap(ClassLoader loader) { return null; }
+ public void readList(List outVal, ClassLoader loader) {}
+ public void readMap(Map outVal, ClassLoader loader) {}
+ public <T extends Parcelable> T readParcelable(ClassLoader loader) { return null; }
+ public Parcelable[] readParcelableArray(ClassLoader loader) { return null; }
+ public Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) { return null; }
+ public <T extends Parcelable> List<T> readParcelableList(List<T> list, ClassLoader cl) { return null; }
+ public Serializable readSerializable() { return null; }
+ public <T> SparseArray<T> readSparseArray(ClassLoader loader) { return null; }
+
+ // Replacements
+ public <T> T[] readArray(ClassLoader loader, Class<T> clazz) { return null; }
+ public <T> ArrayList<T> readArrayList(ClassLoader loader, Class<? extends T> clazz) { return null; }
+ public <K, V> HashMap<K,V> readHashMap(ClassLoader loader, Class<? extends K> clazzKey, Class<? extends V> clazzValue) { return null; }
+ public <T> void readList(List<? super T> outVal, ClassLoader loader, Class<T> clazz) {}
+ public <K, V> void readMap(Map<? super K, ? super V> outVal, ClassLoader loader, Class<K> clazzKey, Class<V> clazzValue) {}
+ public <T> T readParcelable(ClassLoader loader, Class<T> clazz) { return null; }
+ public <T> T[] readParcelableArray(ClassLoader loader, Class<T> clazz) { return null; }
+ public <T> Parcelable.Creator<T> readParcelableCreator(ClassLoader loader, Class<T> clazz) { return null; }
+ public <T> List<T> readParcelableList(List<T> list, ClassLoader cl, Class<T> clazz) { return null; }
+ public <T> T readSerializable(ClassLoader loader, Class<T> clazz) { return null; }
+ public <T> SparseArray<T> readSparseArray(ClassLoader loader, Class<? extends T> clazz) { return null; }
+ }
+ """
+ ).indented(),
+ java(
+ """
+ package android.os;
+ public interface Parcelable {}
+ """
+ ).indented(),
+ java(
+ """
+ package android.content;
+ public class Intent implements Parcelable, Cloneable {}
+ """
+ ).indented(),
+ java(
+ """
+ package android.util;
+ public class SparseArray<E> implements Cloneable {}
+ """
+ ).indented(),
+ )
+
+ // Substitutes "backslash + new line" with an empty string to imitate line continuation
+ private fun String.addLineContinuation(): String = this.trimIndent().replace("\\\n", "")
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java
index f1e84b1d8a33..b44e8b42f052 100644
--- a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java
@@ -20,7 +20,7 @@ import java.util.List;
public class Utils {
- public static final int ASM_VERSION = Opcodes.ASM7;
+ public static final int ASM_VERSION = Opcodes.ASM9;
/**
* Reads a comma separated configuration similar to the Jack definition.
diff --git a/tools/preload-check/device/src/com/android/preload/check/Util.java b/tools/preload-check/device/src/com/android/preload/check/Util.java
index fccea0a0c107..f521c95839f1 100644
--- a/tools/preload-check/device/src/com/android/preload/check/Util.java
+++ b/tools/preload-check/device/src/com/android/preload/check/Util.java
@@ -25,8 +25,8 @@ import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.LinkedList;
import java.util.List;
public class Util {
@@ -48,7 +48,7 @@ public class Util {
Class<?> vmClassLoaderClass = Class.forName("java.lang.VMClassLoader");
Method getResources = vmClassLoaderClass.getDeclaredMethod("getResources", String.class);
getResources.setAccessible(true);
- LinkedList<DexFile> res = new LinkedList<>();
+ ArrayList<DexFile> res = new ArrayList<>();
for (int i = 1;; i++) {
try {
String name = "classes" + (i > 1 ? String.valueOf(i) : "") + ".dex";
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index 82a5dac21160..7059c52ddc76 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -7,27 +7,33 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-java_plugin {
- name: "intdef-annotation-processor",
-
- processor_class: "android.processor.IntDefProcessor",
+java_library_host {
+ name: "libintdef-annotation-processor",
srcs: [
":framework-annotations",
"src/**/*.java",
- "src/**/*.kt"
+ "src/**/*.kt",
],
use_tools_jar: true,
}
+java_plugin {
+ name: "intdef-annotation-processor",
+
+ processor_class: "android.processor.IntDefProcessor",
+
+ static_libs: ["libintdef-annotation-processor"],
+}
+
java_test_host {
name: "intdef-annotation-processor-test",
srcs: [
"test/**/*.java",
- "test/**/*.kt"
- ],
+ "test/**/*.kt",
+ ],
java_resource_dirs: ["test/resources"],
static_libs: [
@@ -35,7 +41,7 @@ java_test_host {
"truth-prebuilt",
"junit",
"guava",
- "intdef-annotation-processor"
+ "libintdef-annotation-processor",
],
test_suites: ["general-tests"],
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index ea9974f06a64..877a1d2b5fb3 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -7,10 +7,8 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-java_plugin {
- name: "view-inspector-annotation-processor",
-
- processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+java_library_host {
+ name: "libview-inspector-annotation-processor",
srcs: ["src/java/**/*.java"],
java_resource_dirs: ["src/resources"],
@@ -23,6 +21,16 @@ java_plugin {
use_tools_jar: true,
}
+java_plugin {
+ name: "view-inspector-annotation-processor",
+
+ processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+
+ static_libs: [
+ "libview-inspector-annotation-processor",
+ ],
+}
+
java_test_host {
name: "view-inspector-annotation-processor-test",
@@ -32,7 +40,7 @@ java_test_host {
static_libs: [
"junit",
"guava",
- "view-inspector-annotation-processor"
+ "libview-inspector-annotation-processor",
],
test_suites: ["general-tests"],
diff --git a/tools/validatekeymaps/OWNERS b/tools/validatekeymaps/OWNERS
index 0313a40f7270..4c20c4dc9d35 100644
--- a/tools/validatekeymaps/OWNERS
+++ b/tools/validatekeymaps/OWNERS
@@ -1,2 +1 @@
-michaelwr@google.com
-svv@google.com
+include /INPUT_OWNERS